activerecord 7.0.8.7 → 7.1.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1339 -1572
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +16 -11
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +12 -9
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +193 -97
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
- data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +128 -138
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +89 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +118 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +100 -4
- data/lib/active_record/migration/compatibility.rb +131 -5
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +213 -109
- data/lib/active_record/model_schema.rb +47 -27
- data/lib/active_record/nested_attributes.rb +28 -3
- data/lib/active_record/normalization.rb +158 -0
- data/lib/active_record/persistence.rb +183 -33
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +10 -5
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +169 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +152 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +85 -15
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +351 -62
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +41 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +10 -1
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +26 -14
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +36 -10
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +52 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -4,138 +4,57 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module MySQL
|
6
6
|
module DatabaseStatements
|
7
|
-
|
8
|
-
def select_all(*, **) # :nodoc:
|
9
|
-
result = if ExplainRegistry.collect? && prepared_statements
|
10
|
-
unprepared_statement { super }
|
11
|
-
else
|
12
|
-
super
|
13
|
-
end
|
14
|
-
@connection.abandon_results!
|
15
|
-
result
|
16
|
-
end
|
17
|
-
|
18
|
-
def query(sql, name = nil) # :nodoc:
|
19
|
-
execute(sql, name).to_a
|
20
|
-
end
|
21
|
-
|
22
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
7
|
+
READ_QUERY = AbstractAdapter.build_read_query_regexp(
|
23
8
|
:desc, :describe, :set, :show, :use, :kill
|
24
9
|
) # :nodoc:
|
25
10
|
private_constant :READ_QUERY
|
26
11
|
|
12
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
13
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
14
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
15
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
16
|
+
|
27
17
|
def write_query?(sql) # :nodoc:
|
28
18
|
!READ_QUERY.match?(sql)
|
29
19
|
rescue ArgumentError # Invalid encoding
|
30
20
|
!READ_QUERY.match?(sql.b)
|
31
21
|
end
|
32
22
|
|
33
|
-
def
|
34
|
-
|
23
|
+
def high_precision_current_timestamp
|
24
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
25
|
+
end
|
26
|
+
|
27
|
+
def explain(arel, binds = [], options = [])
|
28
|
+
sql = build_explain_clause(options) + " " + to_sql(arel, binds)
|
35
29
|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
36
|
-
result =
|
30
|
+
result = internal_exec_query(sql, "EXPLAIN", binds)
|
37
31
|
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
38
32
|
|
39
33
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
40
34
|
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
sql = transform_query(sql)
|
45
|
-
check_if_write_query(sql)
|
36
|
+
def build_explain_clause(options = [])
|
37
|
+
return "EXPLAIN" if options.empty?
|
46
38
|
|
47
|
-
|
48
|
-
end
|
39
|
+
explain_clause = "EXPLAIN #{options.join(" ").upcase}"
|
49
40
|
|
50
|
-
|
51
|
-
|
52
|
-
execute_and_free(sql, name, async: async) do |result|
|
53
|
-
if result
|
54
|
-
build_result(columns: result.fields, rows: result.to_a)
|
55
|
-
else
|
56
|
-
build_result(columns: [], rows: [])
|
57
|
-
end
|
58
|
-
end
|
59
|
-
else
|
60
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
61
|
-
if result
|
62
|
-
build_result(columns: result.fields, rows: result.to_a)
|
63
|
-
else
|
64
|
-
build_result(columns: [], rows: [])
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
71
|
-
if without_prepared_statement?(binds)
|
72
|
-
@lock.synchronize do
|
73
|
-
execute_and_free(sql, name) { @connection.affected_rows }
|
74
|
-
end
|
41
|
+
if analyze_without_explain? && explain_clause.include?("ANALYZE")
|
42
|
+
explain_clause.sub("EXPLAIN ", "")
|
75
43
|
else
|
76
|
-
|
44
|
+
explain_clause
|
77
45
|
end
|
78
46
|
end
|
79
|
-
alias :exec_update :exec_delete
|
80
|
-
|
81
|
-
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
82
|
-
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
83
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
84
|
-
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
85
|
-
|
86
|
-
def high_precision_current_timestamp
|
87
|
-
HIGH_PRECISION_CURRENT_TIMESTAMP
|
88
|
-
end
|
89
47
|
|
90
48
|
private
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
95
|
-
|
96
|
-
super
|
97
|
-
end
|
98
|
-
|
99
|
-
def execute_batch(statements, name = nil)
|
100
|
-
statements = statements.map { |sql| transform_query(sql) }
|
101
|
-
combine_multi_statements(statements).each do |statement|
|
102
|
-
raw_execute(statement, name)
|
103
|
-
@connection.abandon_results!
|
104
|
-
end
|
49
|
+
# https://mariadb.com/kb/en/analyze-statement/
|
50
|
+
def analyze_without_explain?
|
51
|
+
mariadb? && database_version >= "10.1.0"
|
105
52
|
end
|
106
53
|
|
107
54
|
def default_insert_value(column)
|
108
55
|
super unless column.auto_increment?
|
109
56
|
end
|
110
57
|
|
111
|
-
def last_inserted_id(result)
|
112
|
-
@connection.last_id
|
113
|
-
end
|
114
|
-
|
115
|
-
def multi_statements_enabled?
|
116
|
-
flags = @config[:flags]
|
117
|
-
|
118
|
-
if flags.is_a?(Array)
|
119
|
-
flags.include?("MULTI_STATEMENTS")
|
120
|
-
else
|
121
|
-
flags.anybits?(Mysql2::Client::MULTI_STATEMENTS)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def with_multi_statements
|
126
|
-
multi_statements_was = multi_statements_enabled?
|
127
|
-
|
128
|
-
unless multi_statements_was
|
129
|
-
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
130
|
-
end
|
131
|
-
|
132
|
-
yield
|
133
|
-
ensure
|
134
|
-
unless multi_statements_was
|
135
|
-
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
58
|
def combine_multi_statements(total_sql)
|
140
59
|
total_sql.each_with_object([]) do |sql, total_sql_chunks|
|
141
60
|
previous_packet = total_sql_chunks.last
|
@@ -162,46 +81,6 @@ module ActiveRecord
|
|
162
81
|
def max_allowed_packet
|
163
82
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
164
83
|
end
|
165
|
-
|
166
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
167
|
-
sql = transform_query(sql)
|
168
|
-
check_if_write_query(sql)
|
169
|
-
|
170
|
-
materialize_transactions
|
171
|
-
mark_transaction_written_if_write(sql)
|
172
|
-
|
173
|
-
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
174
|
-
# made since we established the connection
|
175
|
-
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
176
|
-
|
177
|
-
type_casted_binds = type_casted_binds(binds)
|
178
|
-
|
179
|
-
log(sql, name, binds, type_casted_binds, async: async) do
|
180
|
-
if cache_stmt
|
181
|
-
stmt = @statements[sql] ||= @connection.prepare(sql)
|
182
|
-
else
|
183
|
-
stmt = @connection.prepare(sql)
|
184
|
-
end
|
185
|
-
|
186
|
-
begin
|
187
|
-
result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
188
|
-
stmt.execute(*type_casted_binds)
|
189
|
-
end
|
190
|
-
rescue Mysql2::Error => e
|
191
|
-
if cache_stmt
|
192
|
-
@statements.delete(sql)
|
193
|
-
else
|
194
|
-
stmt.close
|
195
|
-
end
|
196
|
-
raise e
|
197
|
-
end
|
198
|
-
|
199
|
-
ret = yield stmt, result
|
200
|
-
result.free if result
|
201
|
-
stmt.close unless cache_stmt
|
202
|
-
ret
|
203
|
-
end
|
204
|
-
end
|
205
84
|
end
|
206
85
|
end
|
207
86
|
end
|
@@ -9,20 +9,23 @@ module ActiveRecord
|
|
9
9
|
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
10
10
|
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
11
11
|
|
12
|
-
def
|
12
|
+
def cast_bound_value(value)
|
13
13
|
case value
|
14
14
|
when Rational
|
15
|
-
|
16
|
-
when Numeric
|
17
|
-
|
15
|
+
value.to_f.to_s
|
16
|
+
when Numeric
|
17
|
+
value.to_s
|
18
18
|
when BigDecimal
|
19
|
-
|
19
|
+
value.to_s("F")
|
20
20
|
when true
|
21
|
-
"
|
21
|
+
"1"
|
22
22
|
when false
|
23
|
-
"
|
23
|
+
"0"
|
24
|
+
when ActiveSupport::Duration
|
25
|
+
warn_quote_duration_deprecated
|
26
|
+
value.to_s
|
24
27
|
else
|
25
|
-
|
28
|
+
value
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
@@ -63,14 +66,14 @@ module ActiveRecord
|
|
63
66
|
end
|
64
67
|
|
65
68
|
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
|
66
|
-
# of Strings since
|
69
|
+
# of Strings since MySQL adapters are able to handle those classes more efficiently.
|
67
70
|
def type_cast(value) # :nodoc:
|
68
71
|
case value
|
69
72
|
when ActiveSupport::TimeWithZone
|
70
73
|
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
71
74
|
# we need to transform it to Time objects but we don't want to
|
72
75
|
# transform Time objects to themselves.
|
73
|
-
if
|
76
|
+
if default_timezone == :utc
|
74
77
|
value.getutc
|
75
78
|
else
|
76
79
|
value.getlocal
|
@@ -95,7 +98,7 @@ module ActiveRecord
|
|
95
98
|
(
|
96
99
|
(?:
|
97
100
|
# `table_name`.`column_name` | function(one or no argument)
|
98
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)
|
101
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
99
102
|
)
|
100
103
|
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
101
104
|
)
|
@@ -108,8 +111,9 @@ module ActiveRecord
|
|
108
111
|
(
|
109
112
|
(?:
|
110
113
|
# `table_name`.`column_name` | function(one or no argument)
|
111
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)
|
114
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
112
115
|
)
|
116
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
113
117
|
(?:\s+ASC|\s+DESC)?
|
114
118
|
)
|
115
119
|
(?:\s*,\s*\g<1>)*
|
@@ -24,6 +24,15 @@ module ActiveRecord
|
|
24
24
|
add_column_position!(change_column_sql, column_options(o.column))
|
25
25
|
end
|
26
26
|
|
27
|
+
def visit_ChangeColumnDefaultDefinition(o)
|
28
|
+
sql = +"ALTER COLUMN #{quote_column_name(o.column.name)} "
|
29
|
+
if o.default.nil? && !o.column.null
|
30
|
+
sql << "DROP DEFAULT"
|
31
|
+
else
|
32
|
+
sql << "SET DEFAULT #{quote_default_expression(o.default, o.column)}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
27
36
|
def visit_CreateIndexDefinition(o)
|
28
37
|
sql = visit_IndexDefinition(o.index, true)
|
29
38
|
sql << " #{o.algorithm}" if o.algorithm
|
@@ -57,6 +57,7 @@ module ActiveRecord
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
# = Active Record MySQL Adapter \Table Definition
|
60
61
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
61
62
|
include ColumnMethods
|
62
63
|
|
@@ -85,6 +86,10 @@ module ActiveRecord
|
|
85
86
|
end
|
86
87
|
|
87
88
|
private
|
89
|
+
def valid_column_definition_options
|
90
|
+
super + [:auto_increment, :charset, :as, :size, :unsigned, :first, :after, :type, :stored]
|
91
|
+
end
|
92
|
+
|
88
93
|
def aliased_types(name, fallback)
|
89
94
|
fallback
|
90
95
|
end
|
@@ -98,6 +103,7 @@ module ActiveRecord
|
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
106
|
+
# = Active Record MySQL Adapter \Table
|
101
107
|
class Table < ActiveRecord::ConnectionAdapters::Table
|
102
108
|
include ColumnMethods
|
103
109
|
end
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
if column.collation
|
67
67
|
@table_collation_cache ||= {}
|
68
68
|
@table_collation_cache[table_name] ||=
|
69
|
-
@connection.
|
69
|
+
@connection.internal_exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
|
70
70
|
column.collation.inspect if column.collation != @table_collation_cache[table_name]
|
71
71
|
end
|
72
72
|
end
|
@@ -57,9 +57,9 @@ module ActiveRecord
|
|
57
57
|
orders = options.delete(:orders)
|
58
58
|
lengths = options.delete(:lengths)
|
59
59
|
|
60
|
-
columns = index[-1].
|
60
|
+
columns = index[-1].to_h { |name|
|
61
61
|
[ name.to_sym, expressions[name] || +quote_column_name(name) ]
|
62
|
-
}
|
62
|
+
}
|
63
63
|
|
64
64
|
index[-1] = add_options_for_index_columns(
|
65
65
|
columns, order: orders, length: lengths
|
@@ -125,6 +125,10 @@ module ActiveRecord
|
|
125
125
|
256 # https://dev.mysql.com/doc/refman/en/identifiers.html
|
126
126
|
end
|
127
127
|
|
128
|
+
def schema_creation # :nodoc:
|
129
|
+
MySQL::SchemaCreation.new(self)
|
130
|
+
end
|
131
|
+
|
128
132
|
private
|
129
133
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
130
134
|
|
@@ -150,8 +154,8 @@ module ActiveRecord
|
|
150
154
|
@default_row_format
|
151
155
|
end
|
152
156
|
|
153
|
-
def
|
154
|
-
|
157
|
+
def valid_primary_key_options
|
158
|
+
super + [:unsigned]
|
155
159
|
end
|
156
160
|
|
157
161
|
def create_table_definition(name, **options)
|
@@ -171,7 +175,7 @@ module ActiveRecord
|
|
171
175
|
end
|
172
176
|
end
|
173
177
|
|
174
|
-
def new_column_from_field(table_name, field)
|
178
|
+
def new_column_from_field(table_name, field, _definitions)
|
175
179
|
field_name = field.fetch(:Field)
|
176
180
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
177
181
|
default, default_function = field[:Default], nil
|
@@ -225,14 +229,15 @@ module ActiveRecord
|
|
225
229
|
def data_source_sql(name = nil, type: nil)
|
226
230
|
scope = quoted_scope(name, type: type)
|
227
231
|
|
228
|
-
sql = +"SELECT table_name FROM
|
229
|
-
sql << " WHERE table_schema = #{scope[:schema]}
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
sql << " WHERE #{conditions.join(" AND ")}"
|
232
|
+
sql = +"SELECT table_name FROM information_schema.tables"
|
233
|
+
sql << " WHERE table_schema = #{scope[:schema]}"
|
234
|
+
|
235
|
+
if scope[:name]
|
236
|
+
sql << " AND table_name = #{scope[:name]}"
|
237
|
+
sql << " AND table_name IN (SELECT table_name FROM information_schema.tables WHERE table_schema = #{scope[:schema]})"
|
235
238
|
end
|
239
|
+
|
240
|
+
sql << " AND table_type = #{scope[:type]}" if scope[:type]
|
236
241
|
sql
|
237
242
|
end
|
238
243
|
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Mysql2
|
6
|
+
module DatabaseStatements
|
7
|
+
# Returns an ActiveRecord::Result instance.
|
8
|
+
def select_all(*, **) # :nodoc:
|
9
|
+
result = nil
|
10
|
+
with_raw_connection do |conn|
|
11
|
+
result = if ExplainRegistry.collect? && prepared_statements
|
12
|
+
unprepared_statement { super }
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
conn.abandon_results!
|
17
|
+
end
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
22
|
+
if without_prepared_statement?(binds)
|
23
|
+
execute_and_free(sql, name, async: async) do |result|
|
24
|
+
if result
|
25
|
+
build_result(columns: result.fields, rows: result.to_a)
|
26
|
+
else
|
27
|
+
build_result(columns: [], rows: [])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
32
|
+
if result
|
33
|
+
build_result(columns: result.fields, rows: result.to_a)
|
34
|
+
else
|
35
|
+
build_result(columns: [], rows: [])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
42
|
+
if without_prepared_statement?(binds)
|
43
|
+
with_raw_connection do |conn|
|
44
|
+
@affected_rows_before_warnings = nil
|
45
|
+
execute_and_free(sql, name) { @affected_rows_before_warnings || conn.affected_rows }
|
46
|
+
end
|
47
|
+
else
|
48
|
+
exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias :exec_update :exec_delete
|
52
|
+
|
53
|
+
private
|
54
|
+
def sync_timezone_changes(raw_connection)
|
55
|
+
raw_connection.query_options[:database_timezone] = default_timezone
|
56
|
+
end
|
57
|
+
|
58
|
+
def execute_batch(statements, name = nil)
|
59
|
+
statements = statements.map { |sql| transform_query(sql) }
|
60
|
+
combine_multi_statements(statements).each do |statement|
|
61
|
+
with_raw_connection do |conn|
|
62
|
+
raw_execute(statement, name)
|
63
|
+
conn.abandon_results!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def last_inserted_id(result)
|
69
|
+
@raw_connection&.last_id
|
70
|
+
end
|
71
|
+
|
72
|
+
def multi_statements_enabled?
|
73
|
+
flags = @config[:flags]
|
74
|
+
|
75
|
+
if flags.is_a?(Array)
|
76
|
+
flags.include?("MULTI_STATEMENTS")
|
77
|
+
else
|
78
|
+
flags.anybits?(::Mysql2::Client::MULTI_STATEMENTS)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def with_multi_statements
|
83
|
+
if multi_statements_enabled?
|
84
|
+
return yield
|
85
|
+
end
|
86
|
+
|
87
|
+
with_raw_connection do |conn|
|
88
|
+
conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
89
|
+
|
90
|
+
yield
|
91
|
+
ensure
|
92
|
+
conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
97
|
+
log(sql, name, async: async) do
|
98
|
+
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
99
|
+
sync_timezone_changes(conn)
|
100
|
+
result = conn.query(sql)
|
101
|
+
handle_warnings(sql)
|
102
|
+
result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
108
|
+
sql = transform_query(sql)
|
109
|
+
check_if_write_query(sql)
|
110
|
+
|
111
|
+
mark_transaction_written_if_write(sql)
|
112
|
+
|
113
|
+
type_casted_binds = type_casted_binds(binds)
|
114
|
+
|
115
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
116
|
+
with_raw_connection do |conn|
|
117
|
+
sync_timezone_changes(conn)
|
118
|
+
|
119
|
+
if cache_stmt
|
120
|
+
stmt = @statements[sql] ||= conn.prepare(sql)
|
121
|
+
else
|
122
|
+
stmt = conn.prepare(sql)
|
123
|
+
end
|
124
|
+
|
125
|
+
begin
|
126
|
+
result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
127
|
+
stmt.execute(*type_casted_binds)
|
128
|
+
end
|
129
|
+
rescue ::Mysql2::Error => e
|
130
|
+
if cache_stmt
|
131
|
+
@statements.delete(sql)
|
132
|
+
else
|
133
|
+
stmt.close
|
134
|
+
end
|
135
|
+
raise e
|
136
|
+
end
|
137
|
+
|
138
|
+
ret = yield stmt, result
|
139
|
+
result.free if result
|
140
|
+
stmt.close unless cache_stmt
|
141
|
+
ret
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|