activerecord 7.1.5.2 → 8.1.2.1
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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +268 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +250 -315
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
|
@@ -42,7 +42,7 @@ module ActiveRecord
|
|
|
42
42
|
date: { name: "date" },
|
|
43
43
|
binary: { name: "blob" },
|
|
44
44
|
blob: { name: "blob" },
|
|
45
|
-
boolean: { name: "
|
|
45
|
+
boolean: { name: "boolean" },
|
|
46
46
|
json: { name: "json" },
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -79,7 +79,11 @@ module ActiveRecord
|
|
|
79
79
|
|
|
80
80
|
args << config.database
|
|
81
81
|
|
|
82
|
-
find_cmd_and_exec([
|
|
82
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:mysql], *args)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def native_database_types # :nodoc:
|
|
86
|
+
NATIVE_DATABASE_TYPES
|
|
83
87
|
end
|
|
84
88
|
end
|
|
85
89
|
|
|
@@ -98,7 +102,7 @@ module ActiveRecord
|
|
|
98
102
|
end
|
|
99
103
|
|
|
100
104
|
def supports_index_sort_order?
|
|
101
|
-
|
|
105
|
+
mariadb? ? database_version >= "10.8.1" : database_version >= "8.0.1"
|
|
102
106
|
end
|
|
103
107
|
|
|
104
108
|
def supports_expression_index?
|
|
@@ -138,7 +142,7 @@ module ActiveRecord
|
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
def supports_datetime_with_precision?
|
|
141
|
-
|
|
145
|
+
true
|
|
142
146
|
end
|
|
143
147
|
|
|
144
148
|
def supports_virtual_columns?
|
|
@@ -170,6 +174,24 @@ module ActiveRecord
|
|
|
170
174
|
true
|
|
171
175
|
end
|
|
172
176
|
|
|
177
|
+
def supports_insert_returning?
|
|
178
|
+
mariadb? && database_version >= "10.5.0"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def return_value_after_insert?(column) # :nodoc:
|
|
182
|
+
supports_insert_returning? ? column.auto_populated? : column.auto_increment?
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# See https://dev.mysql.com/doc/refman/8.0/en/invisible-indexes.html for more details on MySQL feature.
|
|
186
|
+
# See https://mariadb.com/kb/en/ignored-indexes/ for more details on the MariaDB feature.
|
|
187
|
+
def supports_disabling_indexes?
|
|
188
|
+
if mariadb?
|
|
189
|
+
database_version >= "10.6.0"
|
|
190
|
+
else
|
|
191
|
+
database_version >= "8.0.0"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
173
195
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
|
174
196
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
|
175
197
|
end
|
|
@@ -178,10 +200,6 @@ module ActiveRecord
|
|
|
178
200
|
query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
|
|
179
201
|
end
|
|
180
202
|
|
|
181
|
-
def native_database_types
|
|
182
|
-
NATIVE_DATABASE_TYPES
|
|
183
|
-
end
|
|
184
|
-
|
|
185
203
|
def index_algorithms
|
|
186
204
|
{
|
|
187
205
|
default: "ALGORITHM = DEFAULT",
|
|
@@ -191,14 +209,6 @@ module ActiveRecord
|
|
|
191
209
|
}
|
|
192
210
|
end
|
|
193
211
|
|
|
194
|
-
# HELPER METHODS ===========================================
|
|
195
|
-
|
|
196
|
-
# The two drivers have slightly different ways of yielding hashes of results, so
|
|
197
|
-
# this method must be implemented to provide a uniform interface.
|
|
198
|
-
def each_hash(result) # :nodoc:
|
|
199
|
-
raise NotImplementedError
|
|
200
|
-
end
|
|
201
|
-
|
|
202
212
|
# Must return the MySQL error number from the exception, if the exception has an
|
|
203
213
|
# error number.
|
|
204
214
|
def error_number(exception) # :nodoc:
|
|
@@ -214,7 +224,7 @@ module ActiveRecord
|
|
|
214
224
|
update("SET FOREIGN_KEY_CHECKS = 0")
|
|
215
225
|
yield
|
|
216
226
|
ensure
|
|
217
|
-
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
|
227
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}") if active?
|
|
218
228
|
end
|
|
219
229
|
end
|
|
220
230
|
|
|
@@ -222,24 +232,19 @@ module ActiveRecord
|
|
|
222
232
|
# DATABASE STATEMENTS ======================================
|
|
223
233
|
#++
|
|
224
234
|
|
|
225
|
-
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
|
226
|
-
# to write stuff in an abstract way without concerning ourselves about whether it
|
|
227
|
-
# needs to be explicitly freed or not.
|
|
228
|
-
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
|
229
|
-
sql = transform_query(sql)
|
|
230
|
-
check_if_write_query(sql)
|
|
231
|
-
|
|
232
|
-
mark_transaction_written_if_write(sql)
|
|
233
|
-
yield raw_execute(sql, name, async: async)
|
|
234
|
-
end
|
|
235
|
-
|
|
236
235
|
def begin_db_transaction # :nodoc:
|
|
237
236
|
internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
|
|
238
237
|
end
|
|
239
238
|
|
|
240
239
|
def begin_isolated_db_transaction(isolation) # :nodoc:
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
# From MySQL manual: The [SET TRANSACTION] statement applies only to the next single transaction performed within the session.
|
|
241
|
+
# So we don't need to implement #reset_isolation_level
|
|
242
|
+
execute_batch(
|
|
243
|
+
["SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "BEGIN"],
|
|
244
|
+
"TRANSACTION",
|
|
245
|
+
allow_retry: true,
|
|
246
|
+
materialize_transactions: false,
|
|
247
|
+
)
|
|
243
248
|
end
|
|
244
249
|
|
|
245
250
|
def commit_db_transaction # :nodoc:
|
|
@@ -339,7 +344,7 @@ module ActiveRecord
|
|
|
339
344
|
rename_table_indexes(table_name, new_name, **options)
|
|
340
345
|
end
|
|
341
346
|
|
|
342
|
-
# Drops a table from the database.
|
|
347
|
+
# Drops a table or tables from the database.
|
|
343
348
|
#
|
|
344
349
|
# [<tt>:force</tt>]
|
|
345
350
|
# Set to +:cascade+ to drop dependent objects as well.
|
|
@@ -353,10 +358,10 @@ module ActiveRecord
|
|
|
353
358
|
#
|
|
354
359
|
# Although this command ignores most +options+ and the block if one is given,
|
|
355
360
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
|
356
|
-
# In that case, +options+ and the block will be used by create_table.
|
|
357
|
-
def drop_table(
|
|
358
|
-
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
359
|
-
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
|
361
|
+
# In that case, +options+ and the block will be used by #create_table except if you provide more than one table which is not supported.
|
|
362
|
+
def drop_table(*table_names, **options)
|
|
363
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
364
|
+
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{table_names.map { |table_name| quote_table_name(table_name) }.join(', ')}#{' CASCADE' if options[:force] == :cascade}"
|
|
360
365
|
end
|
|
361
366
|
|
|
362
367
|
def rename_index(table_name, old_name, new_name)
|
|
@@ -410,7 +415,11 @@ module ActiveRecord
|
|
|
410
415
|
type ||= column.sql_type
|
|
411
416
|
|
|
412
417
|
unless options.key?(:default)
|
|
413
|
-
options[:default] = column.
|
|
418
|
+
options[:default] = if column.default_function
|
|
419
|
+
-> { column.default_function }
|
|
420
|
+
else
|
|
421
|
+
column.default
|
|
422
|
+
end
|
|
414
423
|
end
|
|
415
424
|
|
|
416
425
|
unless options.key?(:null)
|
|
@@ -456,6 +465,24 @@ module ActiveRecord
|
|
|
456
465
|
CreateIndexDefinition.new(index, algorithm)
|
|
457
466
|
end
|
|
458
467
|
|
|
468
|
+
def enable_index(table_name, index_name) # :nodoc:
|
|
469
|
+
raise NotImplementedError unless supports_disabling_indexes?
|
|
470
|
+
|
|
471
|
+
query = <<~SQL
|
|
472
|
+
ALTER TABLE #{quote_table_name(table_name)} ALTER INDEX #{index_name} #{mariadb? ? "NOT IGNORED" : "VISIBLE"}
|
|
473
|
+
SQL
|
|
474
|
+
execute(query)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def disable_index(table_name, index_name) # :nodoc:
|
|
478
|
+
raise NotImplementedError unless supports_disabling_indexes?
|
|
479
|
+
|
|
480
|
+
query = <<~SQL
|
|
481
|
+
ALTER TABLE #{quote_table_name(table_name)} ALTER INDEX #{index_name} #{mariadb? ? "IGNORED" : "INVISIBLE"}
|
|
482
|
+
SQL
|
|
483
|
+
execute(query)
|
|
484
|
+
end
|
|
485
|
+
|
|
459
486
|
def add_sql_comment!(sql, comment) # :nodoc:
|
|
460
487
|
sql << " COMMENT #{quote(comment)}" if comment.present?
|
|
461
488
|
sql
|
|
@@ -576,7 +603,7 @@ module ActiveRecord
|
|
|
576
603
|
|
|
577
604
|
# SHOW VARIABLES LIKE 'name'
|
|
578
605
|
def show_variable(name)
|
|
579
|
-
query_value("SELECT @@#{name}", "SCHEMA")
|
|
606
|
+
query_value("SELECT @@#{name}", "SCHEMA", materialize_transactions: false, allow_retry: true)
|
|
580
607
|
rescue ActiveRecord::StatementInvalid
|
|
581
608
|
nil
|
|
582
609
|
end
|
|
@@ -635,22 +662,26 @@ module ActiveRecord
|
|
|
635
662
|
end
|
|
636
663
|
|
|
637
664
|
def build_insert_sql(insert) # :nodoc:
|
|
638
|
-
|
|
665
|
+
# Can use any column as it will be assigned to itself.
|
|
666
|
+
no_op_column = quote_column_name(insert.keys.first) if insert.keys.first
|
|
639
667
|
|
|
640
668
|
# MySQL 8.0.19 replaces `VALUES(<expression>)` clauses with row and column alias names, see https://dev.mysql.com/worklog/task/?id=6312 .
|
|
641
669
|
# then MySQL 8.0.20 deprecates the `VALUES(<expression>)` see https://dev.mysql.com/worklog/task/?id=13325 .
|
|
642
670
|
if supports_insert_raw_alias_syntax?
|
|
643
|
-
|
|
671
|
+
quoted_table_name = insert.model.quoted_table_name
|
|
672
|
+
values_alias = quote_table_name("#{insert.model.table_name.parameterize}_values")
|
|
644
673
|
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
|
|
645
674
|
|
|
646
675
|
if insert.skip_duplicates?
|
|
647
|
-
|
|
676
|
+
if no_op_column
|
|
677
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{quoted_table_name}.#{no_op_column}"
|
|
678
|
+
end
|
|
648
679
|
elsif insert.update_duplicates?
|
|
649
680
|
if insert.raw_update_sql?
|
|
650
681
|
sql = +"INSERT #{insert.into} #{insert.values_list} ON DUPLICATE KEY UPDATE #{insert.raw_update_sql}"
|
|
651
682
|
else
|
|
652
683
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
653
|
-
sql << insert.touch_model_timestamps_unless { |column| "#{
|
|
684
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{quoted_table_name}.#{column}<=>#{values_alias}.#{column}" }
|
|
654
685
|
sql << insert.updatable_columns.map { |column| "#{column}=#{values_alias}.#{column}" }.join(",")
|
|
655
686
|
end
|
|
656
687
|
end
|
|
@@ -658,7 +689,9 @@ module ActiveRecord
|
|
|
658
689
|
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
|
659
690
|
|
|
660
691
|
if insert.skip_duplicates?
|
|
661
|
-
|
|
692
|
+
if no_op_column
|
|
693
|
+
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
|
694
|
+
end
|
|
662
695
|
elsif insert.update_duplicates?
|
|
663
696
|
sql << " ON DUPLICATE KEY UPDATE "
|
|
664
697
|
if insert.raw_update_sql?
|
|
@@ -670,12 +703,24 @@ module ActiveRecord
|
|
|
670
703
|
end
|
|
671
704
|
end
|
|
672
705
|
|
|
706
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
|
673
707
|
sql
|
|
674
708
|
end
|
|
675
709
|
|
|
676
710
|
def check_version # :nodoc:
|
|
677
|
-
if database_version < "5.
|
|
678
|
-
raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.
|
|
711
|
+
if database_version < "5.6.4"
|
|
712
|
+
raise DatabaseVersionError, "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.6.4."
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
#--
|
|
717
|
+
# QUOTING ==================================================
|
|
718
|
+
#++
|
|
719
|
+
|
|
720
|
+
# Quotes strings for use in SQL input.
|
|
721
|
+
def quote_string(string)
|
|
722
|
+
with_raw_connection(allow_retry: true, materialize_transactions: false) do |connection|
|
|
723
|
+
connection.escape(string)
|
|
679
724
|
end
|
|
680
725
|
end
|
|
681
726
|
|
|
@@ -713,12 +758,12 @@ module ActiveRecord
|
|
|
713
758
|
m.alias_type %r(bit)i, "binary"
|
|
714
759
|
end
|
|
715
760
|
|
|
716
|
-
def register_integer_type(mapping, key,
|
|
761
|
+
def register_integer_type(mapping, key, limit:)
|
|
717
762
|
mapping.register_type(key) do |sql_type|
|
|
718
763
|
if /\bunsigned\b/.match?(sql_type)
|
|
719
|
-
Type::UnsignedInteger.new(
|
|
764
|
+
Type::UnsignedInteger.new(limit: limit)
|
|
720
765
|
else
|
|
721
|
-
Type::Integer.new(
|
|
766
|
+
Type::Integer.new(limit: limit)
|
|
722
767
|
end
|
|
723
768
|
end
|
|
724
769
|
end
|
|
@@ -737,9 +782,7 @@ module ActiveRecord
|
|
|
737
782
|
|
|
738
783
|
private
|
|
739
784
|
def strip_whitespace_characters(expression)
|
|
740
|
-
expression
|
|
741
|
-
expression = expression.gsub(/\s{2,}/, " ")
|
|
742
|
-
expression
|
|
785
|
+
expression.gsub('\\\n', "").gsub("x0A", "").squish
|
|
743
786
|
end
|
|
744
787
|
|
|
745
788
|
def extended_type_map_key
|
|
@@ -750,11 +793,14 @@ module ActiveRecord
|
|
|
750
793
|
end
|
|
751
794
|
end
|
|
752
795
|
|
|
753
|
-
def handle_warnings(sql)
|
|
796
|
+
def handle_warnings(_initial_result, sql)
|
|
754
797
|
return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
|
|
755
798
|
|
|
756
|
-
|
|
799
|
+
warning_count = @raw_connection.warning_count
|
|
757
800
|
result = @raw_connection.query("SHOW WARNINGS")
|
|
801
|
+
result = [
|
|
802
|
+
["Warning", nil, "Query had warning_count=#{warning_count} but `SHOW WARNINGS` did not return the warnings. Check MySQL logs or database configuration."],
|
|
803
|
+
] if result.count == 0
|
|
758
804
|
result.each do |level, code, message|
|
|
759
805
|
warning = SQLWarning.new(message, code, level, sql, @pool)
|
|
760
806
|
next if warning_ignored?(warning)
|
|
@@ -767,15 +813,11 @@ module ActiveRecord
|
|
|
767
813
|
warning.level == "Note" || super
|
|
768
814
|
end
|
|
769
815
|
|
|
770
|
-
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
771
|
-
# made since we established the connection
|
|
772
|
-
def sync_timezone_changes(raw_connection)
|
|
773
|
-
end
|
|
774
|
-
|
|
775
816
|
# See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
|
|
776
817
|
ER_DB_CREATE_EXISTS = 1007
|
|
777
818
|
ER_FILSORT_ABORT = 1028
|
|
778
819
|
ER_DUP_ENTRY = 1062
|
|
820
|
+
ER_SERVER_SHUTDOWN = 1053
|
|
779
821
|
ER_NOT_NULL_VIOLATION = 1048
|
|
780
822
|
ER_NO_REFERENCED_ROW = 1216
|
|
781
823
|
ER_ROW_IS_REFERENCED = 1217
|
|
@@ -794,6 +836,8 @@ module ActiveRecord
|
|
|
794
836
|
CR_SERVER_LOST = 2013
|
|
795
837
|
ER_QUERY_TIMEOUT = 3024
|
|
796
838
|
ER_FK_INCOMPATIBLE_COLUMNS = 3780
|
|
839
|
+
ER_CHECK_CONSTRAINT_VIOLATED = 3819
|
|
840
|
+
ER_CONSTRAINT_FAILED = 4025
|
|
797
841
|
ER_CLIENT_INTERACTION_TIMEOUT = 4031
|
|
798
842
|
|
|
799
843
|
def translate_exception(exception, message:, sql:, binds:)
|
|
@@ -804,7 +848,7 @@ module ActiveRecord
|
|
|
804
848
|
else
|
|
805
849
|
super
|
|
806
850
|
end
|
|
807
|
-
when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
851
|
+
when ER_CONNECTION_KILLED, ER_SERVER_SHUTDOWN, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
|
|
808
852
|
ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
809
853
|
when ER_DB_CREATE_EXISTS
|
|
810
854
|
DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
@@ -826,6 +870,8 @@ module ActiveRecord
|
|
|
826
870
|
RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
827
871
|
when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
|
|
828
872
|
NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
873
|
+
when ER_CHECK_CONSTRAINT_VIOLATED, ER_CONSTRAINT_FAILED
|
|
874
|
+
CheckViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
829
875
|
when ER_LOCK_DEADLOCK
|
|
830
876
|
Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
|
831
877
|
when ER_LOCK_WAIT_TIMEOUT
|
|
@@ -894,6 +940,7 @@ module ActiveRecord
|
|
|
894
940
|
end
|
|
895
941
|
|
|
896
942
|
def configure_connection
|
|
943
|
+
super
|
|
897
944
|
variables = @config.fetch(:variables, {}).stringify_keys
|
|
898
945
|
|
|
899
946
|
# Increase timeout so the server doesn't disconnect us.
|
|
@@ -939,13 +986,11 @@ module ActiveRecord
|
|
|
939
986
|
end.join(", ")
|
|
940
987
|
|
|
941
988
|
# ...and send them all in one query
|
|
942
|
-
|
|
989
|
+
raw_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
|
943
990
|
end
|
|
944
991
|
|
|
945
992
|
def column_definitions(table_name) # :nodoc:
|
|
946
|
-
|
|
947
|
-
each_hash(result)
|
|
948
|
-
end
|
|
993
|
+
internal_exec_query("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA", allow_retry: true)
|
|
949
994
|
end
|
|
950
995
|
|
|
951
996
|
def create_table_info(table_name) # :nodoc:
|
|
@@ -1001,7 +1046,11 @@ module ActiveRecord
|
|
|
1001
1046
|
end
|
|
1002
1047
|
|
|
1003
1048
|
def version_string(full_version_string)
|
|
1004
|
-
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1049
|
+
if full_version_string && matches = full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)
|
|
1050
|
+
matches[1]
|
|
1051
|
+
else
|
|
1052
|
+
raise DatabaseVersionError, "Unable to parse MySQL version from #{full_version_string.inspect}"
|
|
1053
|
+
end
|
|
1005
1054
|
end
|
|
1006
1055
|
end
|
|
1007
1056
|
end
|
|
@@ -17,16 +17,22 @@ module ActiveRecord
|
|
|
17
17
|
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
|
18
18
|
# +sql_type_metadata+ is various information about the type of the column
|
|
19
19
|
# +null+ determines if this column allows +NULL+ values.
|
|
20
|
-
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
|
|
20
|
+
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
|
|
21
21
|
@name = name.freeze
|
|
22
|
+
@cast_type = cast_type
|
|
22
23
|
@sql_type_metadata = sql_type_metadata
|
|
23
24
|
@null = null
|
|
24
|
-
@default = default
|
|
25
|
+
@default = default.nil? || cast_type.mutable? ? default : cast_type.deserialize(default)
|
|
25
26
|
@default_function = default_function
|
|
26
27
|
@collation = collation
|
|
27
28
|
@comment = comment
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
def fetch_cast_type(connection) # :nodoc:
|
|
32
|
+
# TODO: Remove fetch_cast_type and the need for connection after we release 8.1.
|
|
33
|
+
@cast_type || connection.lookup_cast_type(sql_type)
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
def has_default?
|
|
31
37
|
!default.nil? || default_function
|
|
32
38
|
end
|
|
@@ -45,6 +51,7 @@ module ActiveRecord
|
|
|
45
51
|
|
|
46
52
|
def init_with(coder)
|
|
47
53
|
@name = coder["name"]
|
|
54
|
+
@cast_type = coder["cast_type"]
|
|
48
55
|
@sql_type_metadata = coder["sql_type_metadata"]
|
|
49
56
|
@null = coder["null"]
|
|
50
57
|
@default = coder["default"]
|
|
@@ -55,6 +62,7 @@ module ActiveRecord
|
|
|
55
62
|
|
|
56
63
|
def encode_with(coder)
|
|
57
64
|
coder["name"] = @name
|
|
65
|
+
coder["cast_type"] = @cast_type
|
|
58
66
|
coder["sql_type_metadata"] = @sql_type_metadata
|
|
59
67
|
coder["null"] = @null
|
|
60
68
|
coder["default"] = @default
|
|
@@ -75,6 +83,7 @@ module ActiveRecord
|
|
|
75
83
|
def ==(other)
|
|
76
84
|
other.is_a?(Column) &&
|
|
77
85
|
name == other.name &&
|
|
86
|
+
cast_type == other.cast_type &&
|
|
78
87
|
default == other.default &&
|
|
79
88
|
sql_type_metadata == other.sql_type_metadata &&
|
|
80
89
|
null == other.null &&
|
|
@@ -88,6 +97,7 @@ module ActiveRecord
|
|
|
88
97
|
Column.hash ^
|
|
89
98
|
name.hash ^
|
|
90
99
|
name.encoding.hash ^
|
|
100
|
+
cast_type.hash ^
|
|
91
101
|
default.hash ^
|
|
92
102
|
sql_type_metadata.hash ^
|
|
93
103
|
null.hash ^
|
|
@@ -100,11 +110,14 @@ module ActiveRecord
|
|
|
100
110
|
false
|
|
101
111
|
end
|
|
102
112
|
|
|
113
|
+
protected
|
|
114
|
+
attr_reader :cast_type
|
|
115
|
+
|
|
103
116
|
private
|
|
104
117
|
def deduplicated
|
|
105
118
|
@name = -name
|
|
106
119
|
@sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
|
|
107
|
-
@default = -default if default
|
|
120
|
+
@default = -default if String === default
|
|
108
121
|
@default_function = -default_function if default_function
|
|
109
122
|
@collation = -collation if collation
|
|
110
123
|
@comment = -comment if comment
|
|
@@ -114,7 +127,7 @@ module ActiveRecord
|
|
|
114
127
|
|
|
115
128
|
class NullColumn < Column
|
|
116
129
|
def initialize(name, **)
|
|
117
|
-
super(name, nil)
|
|
130
|
+
super(name, nil, nil)
|
|
118
131
|
end
|
|
119
132
|
end
|
|
120
133
|
end
|
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
|
11
11
|
|
|
12
12
|
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
|
13
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:
|
|
14
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)", retryable: true).freeze # :nodoc:
|
|
15
15
|
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
|
16
16
|
|
|
17
17
|
def write_query?(sql) # :nodoc:
|
|
@@ -45,14 +45,22 @@ module ActiveRecord
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def default_insert_value(column) # :nodoc:
|
|
49
|
+
super unless column.auto_increment?
|
|
50
|
+
end
|
|
51
|
+
|
|
48
52
|
private
|
|
49
53
|
# https://mariadb.com/kb/en/analyze-statement/
|
|
50
54
|
def analyze_without_explain?
|
|
51
55
|
mariadb? && database_version >= "10.1.0"
|
|
52
56
|
end
|
|
53
57
|
|
|
54
|
-
def
|
|
55
|
-
|
|
58
|
+
def returning_column_values(result)
|
|
59
|
+
if supports_insert_returning?
|
|
60
|
+
result.rows.first
|
|
61
|
+
else
|
|
62
|
+
super
|
|
63
|
+
end
|
|
56
64
|
end
|
|
57
65
|
|
|
58
66
|
def combine_multi_statements(total_sql)
|
|
@@ -6,9 +6,52 @@ module ActiveRecord
|
|
|
6
6
|
module ConnectionAdapters
|
|
7
7
|
module MySQL
|
|
8
8
|
module Quoting # :nodoc:
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
9
11
|
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
|
10
12
|
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
|
11
13
|
|
|
14
|
+
module ClassMethods # :nodoc:
|
|
15
|
+
def column_name_matcher
|
|
16
|
+
/
|
|
17
|
+
\A
|
|
18
|
+
(
|
|
19
|
+
(?:
|
|
20
|
+
# `table_name`.`column_name` | function(one or no argument)
|
|
21
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
22
|
+
)
|
|
23
|
+
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
|
24
|
+
)
|
|
25
|
+
(?:\s*,\s*\g<1>)*
|
|
26
|
+
\z
|
|
27
|
+
/ix
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def column_name_with_order_matcher
|
|
31
|
+
/
|
|
32
|
+
\A
|
|
33
|
+
(
|
|
34
|
+
(?:
|
|
35
|
+
# `table_name`.`column_name` | function(one or no argument)
|
|
36
|
+
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
37
|
+
)
|
|
38
|
+
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
|
39
|
+
(?:\s+ASC|\s+DESC)?
|
|
40
|
+
)
|
|
41
|
+
(?:\s*,\s*\g<1>)*
|
|
42
|
+
\z
|
|
43
|
+
/ix
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def quote_column_name(name)
|
|
47
|
+
QUOTED_COLUMN_NAMES[name] ||= "`#{name.to_s.gsub('`', '``')}`".freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def quote_table_name(name)
|
|
51
|
+
QUOTED_TABLE_NAMES[name] ||= "`#{name.to_s.gsub('`', '``').gsub(".", "`.`")}`".freeze
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
12
55
|
def cast_bound_value(value)
|
|
13
56
|
case value
|
|
14
57
|
when Rational
|
|
@@ -21,22 +64,11 @@ module ActiveRecord
|
|
|
21
64
|
"1"
|
|
22
65
|
when false
|
|
23
66
|
"0"
|
|
24
|
-
when ActiveSupport::Duration
|
|
25
|
-
warn_quote_duration_deprecated
|
|
26
|
-
value.to_s
|
|
27
67
|
else
|
|
28
68
|
value
|
|
29
69
|
end
|
|
30
70
|
end
|
|
31
71
|
|
|
32
|
-
def quote_column_name(name)
|
|
33
|
-
QUOTED_COLUMN_NAMES[name] ||= "`#{super.gsub('`', '``')}`"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def quote_table_name(name)
|
|
37
|
-
QUOTED_TABLE_NAMES[name] ||= super.gsub(".", "`.`").freeze
|
|
38
|
-
end
|
|
39
|
-
|
|
40
72
|
def unquoted_true
|
|
41
73
|
1
|
|
42
74
|
end
|
|
@@ -45,14 +77,6 @@ module ActiveRecord
|
|
|
45
77
|
0
|
|
46
78
|
end
|
|
47
79
|
|
|
48
|
-
def quoted_date(value)
|
|
49
|
-
if supports_datetime_with_precision?
|
|
50
|
-
super
|
|
51
|
-
else
|
|
52
|
-
super.sub(/\.\d{6}\z/, "")
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
80
|
def quoted_binary(value)
|
|
57
81
|
"x'#{value.hex}'"
|
|
58
82
|
end
|
|
@@ -78,49 +102,18 @@ module ActiveRecord
|
|
|
78
102
|
else
|
|
79
103
|
value.getlocal
|
|
80
104
|
end
|
|
81
|
-
when
|
|
105
|
+
when Time
|
|
106
|
+
if default_timezone == :utc
|
|
107
|
+
value.utc? ? value : value.getutc
|
|
108
|
+
else
|
|
109
|
+
value.utc? ? value.getlocal : value
|
|
110
|
+
end
|
|
111
|
+
when Date
|
|
82
112
|
value
|
|
83
113
|
else
|
|
84
114
|
super
|
|
85
115
|
end
|
|
86
116
|
end
|
|
87
|
-
|
|
88
|
-
def column_name_matcher
|
|
89
|
-
COLUMN_NAME
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def column_name_with_order_matcher
|
|
93
|
-
COLUMN_NAME_WITH_ORDER
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
COLUMN_NAME = /
|
|
97
|
-
\A
|
|
98
|
-
(
|
|
99
|
-
(?:
|
|
100
|
-
# `table_name`.`column_name` | function(one or no argument)
|
|
101
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
102
|
-
)
|
|
103
|
-
(?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
|
|
104
|
-
)
|
|
105
|
-
(?:\s*,\s*\g<1>)*
|
|
106
|
-
\z
|
|
107
|
-
/ix
|
|
108
|
-
|
|
109
|
-
COLUMN_NAME_WITH_ORDER = /
|
|
110
|
-
\A
|
|
111
|
-
(
|
|
112
|
-
(?:
|
|
113
|
-
# `table_name`.`column_name` | function(one or no argument)
|
|
114
|
-
((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`) | \w+\((?:|\g<2>)\))
|
|
115
|
-
)
|
|
116
|
-
(?:\s+COLLATE\s+(?:\w+|"\w+"))?
|
|
117
|
-
(?:\s+ASC|\s+DESC)?
|
|
118
|
-
)
|
|
119
|
-
(?:\s*,\s*\g<1>)*
|
|
120
|
-
\z
|
|
121
|
-
/ix
|
|
122
|
-
|
|
123
|
-
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
|
124
117
|
end
|
|
125
118
|
end
|
|
126
119
|
end
|
|
@@ -49,6 +49,8 @@ module ActiveRecord
|
|
|
49
49
|
sql << "USING #{o.using}" if o.using
|
|
50
50
|
sql << "ON #{quote_table_name(o.table)}" if create
|
|
51
51
|
sql << "(#{quoted_columns(o)})"
|
|
52
|
+
sql << "INVISIBLE" if o.disabled? && !mariadb?
|
|
53
|
+
sql << "IGNORED" if o.disabled? && mariadb?
|
|
52
54
|
|
|
53
55
|
add_sql_comment!(sql.join(" "), o.comment)
|
|
54
56
|
end
|