activerecord 6.1.4.1 → 7.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1132 -936
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +34 -27
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +187 -55
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +118 -90
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +6 -21
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +78 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -50
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +29 -18
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +205 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +122 -132
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +16 -32
- data/lib/active_record/delegated_type.rb +52 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +49 -42
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +17 -20
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +107 -3
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +45 -58
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +43 -38
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +243 -61
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +184 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +10 -3
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +120 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +4 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +59 -14
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
36
36
|
include Savepoints
|
37
37
|
|
38
38
|
SIMPLE_INT = /\A\d+\z/
|
39
|
-
COMMENT_REGEX = %r{(
|
39
|
+
COMMENT_REGEX = %r{(?:--.*\n)*|/\*(?:[^*]|\*[^/])*\*/}m
|
40
40
|
|
41
41
|
attr_accessor :pool
|
42
42
|
attr_reader :visitor, :owner, :logger, :lock
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
def self.build_read_query_regexp(*parts) # :nodoc:
|
69
69
|
parts += DEFAULT_READ_QUERY
|
70
70
|
parts = parts.map { |part| /#{part}/i }
|
71
|
-
/\A(?:[
|
71
|
+
/\A(?:[(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/
|
72
72
|
end
|
73
73
|
|
74
74
|
def self.quoted_column_names # :nodoc:
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
88
88
|
@logger = logger
|
89
89
|
@config = config
|
90
90
|
@pool = ActiveRecord::ConnectionAdapters::NullPool.new
|
91
|
-
@idle_since =
|
91
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
92
92
|
@visitor = arel_visitor
|
93
93
|
@statements = build_statement_pool
|
94
94
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
@@ -102,6 +102,25 @@ module ActiveRecord
|
|
102
102
|
)
|
103
103
|
end
|
104
104
|
|
105
|
+
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
|
106
|
+
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
|
107
|
+
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
|
108
|
+
def with_instrumenter(instrumenter, &block) # :nodoc:
|
109
|
+
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
110
|
+
previous_instrumenter = @instrumenter
|
111
|
+
@instrumenter = instrumenter
|
112
|
+
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
113
|
+
ensure
|
114
|
+
@instrumenter = previous_instrumenter
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def check_if_write_query(sql) # :nodoc:
|
119
|
+
if preventing_writes? && write_query?(sql)
|
120
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
105
124
|
def replica?
|
106
125
|
@config[:replica] || false
|
107
126
|
end
|
@@ -121,10 +140,10 @@ module ActiveRecord
|
|
121
140
|
# will return true based on +current_preventing_writes+.
|
122
141
|
def preventing_writes?
|
123
142
|
return true if replica?
|
124
|
-
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord
|
125
|
-
return false if
|
143
|
+
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
|
144
|
+
return false if connection_class.nil?
|
126
145
|
|
127
|
-
|
146
|
+
connection_class.current_preventing_writes
|
128
147
|
end
|
129
148
|
|
130
149
|
def migrations_paths # :nodoc:
|
@@ -159,7 +178,7 @@ module ActiveRecord
|
|
159
178
|
alias :prepared_statements :prepared_statements?
|
160
179
|
|
161
180
|
def prepared_statements_disabled_cache # :nodoc:
|
162
|
-
|
181
|
+
ActiveSupport::IsolatedExecutionState[:active_record_prepared_statements_disabled_cache] ||= Set.new
|
163
182
|
end
|
164
183
|
|
165
184
|
class Version
|
@@ -201,8 +220,20 @@ module ActiveRecord
|
|
201
220
|
@owner = Thread.current
|
202
221
|
end
|
203
222
|
|
204
|
-
def
|
205
|
-
@pool.
|
223
|
+
def connection_class # :nodoc:
|
224
|
+
@pool.connection_class
|
225
|
+
end
|
226
|
+
|
227
|
+
# The role (ie :writing) for the current connection. In a
|
228
|
+
# non-multi role application, `:writing` is returned.
|
229
|
+
def role
|
230
|
+
@pool.role
|
231
|
+
end
|
232
|
+
|
233
|
+
# The shard (ie :default) for the current connection. In
|
234
|
+
# a non-sharded application, `:default` is returned.
|
235
|
+
def shard
|
236
|
+
@pool.shard
|
206
237
|
end
|
207
238
|
|
208
239
|
def schema_cache
|
@@ -223,7 +254,7 @@ module ActiveRecord
|
|
223
254
|
"Current thread: #{Thread.current}."
|
224
255
|
end
|
225
256
|
|
226
|
-
@idle_since =
|
257
|
+
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
227
258
|
@owner = nil
|
228
259
|
else
|
229
260
|
raise ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
@@ -246,7 +277,7 @@ module ActiveRecord
|
|
246
277
|
# Seconds since this connection was returned to the pool
|
247
278
|
def seconds_idle # :nodoc:
|
248
279
|
return 0 if in_use?
|
249
|
-
|
280
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC) - @idle_since
|
250
281
|
end
|
251
282
|
|
252
283
|
def unprepared_statement
|
@@ -344,6 +375,11 @@ module ActiveRecord
|
|
344
375
|
false
|
345
376
|
end
|
346
377
|
|
378
|
+
# Does this adapter support creating deferrable constraints?
|
379
|
+
def supports_deferrable_constraints?
|
380
|
+
false
|
381
|
+
end
|
382
|
+
|
347
383
|
# Does this adapter support creating check constraints?
|
348
384
|
def supports_check_constraints?
|
349
385
|
false
|
@@ -418,6 +454,15 @@ module ActiveRecord
|
|
418
454
|
false
|
419
455
|
end
|
420
456
|
|
457
|
+
def supports_concurrent_connections?
|
458
|
+
true
|
459
|
+
end
|
460
|
+
|
461
|
+
def async_enabled? # :nodoc:
|
462
|
+
supports_concurrent_connections? &&
|
463
|
+
!ActiveRecord.async_query_executor.nil? && !pool.async_executor.nil?
|
464
|
+
end
|
465
|
+
|
421
466
|
# This is meant to be implemented by the adapters that support extensions
|
422
467
|
def disable_extension(name)
|
423
468
|
end
|
@@ -426,6 +471,10 @@ module ActiveRecord
|
|
426
471
|
def enable_extension(name)
|
427
472
|
end
|
428
473
|
|
474
|
+
# This is meant to be implemented by the adapters that support custom enum types
|
475
|
+
def create_enum(*) # :nodoc:
|
476
|
+
end
|
477
|
+
|
429
478
|
def advisory_locks_enabled? # :nodoc:
|
430
479
|
supports_advisory_locks? && @advisory_locks_enabled
|
431
480
|
end
|
@@ -461,6 +510,11 @@ module ActiveRecord
|
|
461
510
|
yield
|
462
511
|
end
|
463
512
|
|
513
|
+
# Override to check all foreign key constraints in a database.
|
514
|
+
def all_foreign_keys_valid?
|
515
|
+
true
|
516
|
+
end
|
517
|
+
|
464
518
|
# CONNECTION MANAGEMENT ====================================
|
465
519
|
|
466
520
|
# Checks whether the connection to the database is still active. This includes
|
@@ -599,78 +653,93 @@ module ActiveRecord
|
|
599
653
|
def check_version # :nodoc:
|
600
654
|
end
|
601
655
|
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
656
|
+
# Returns the version identifier of the schema currently available in
|
657
|
+
# the database. This is generally equal to the number of the highest-
|
658
|
+
# numbered migration that has been executed, or 0 if no schema
|
659
|
+
# information is present / the database is empty.
|
660
|
+
def schema_version
|
661
|
+
migration_context.current_version
|
662
|
+
end
|
663
|
+
|
664
|
+
def field_ordered_value(column, values) # :nodoc:
|
665
|
+
node = Arel::Nodes::Case.new(column)
|
666
|
+
values.each.with_index(1) do |value, order|
|
667
|
+
node.when(value).then(order)
|
607
668
|
end
|
608
669
|
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
670
|
+
Arel::Nodes::Ascending.new(node.else(values.length + 1))
|
671
|
+
end
|
672
|
+
|
673
|
+
class << self
|
674
|
+
private
|
675
|
+
def initialize_type_map(m)
|
676
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
677
|
+
register_class_with_limit m, %r(char)i, Type::String
|
678
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
679
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
680
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
681
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
682
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
683
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
684
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
685
|
+
|
686
|
+
m.alias_type %r(blob)i, "binary"
|
687
|
+
m.alias_type %r(clob)i, "text"
|
688
|
+
m.alias_type %r(timestamp)i, "datetime"
|
689
|
+
m.alias_type %r(numeric)i, "decimal"
|
690
|
+
m.alias_type %r(number)i, "decimal"
|
691
|
+
m.alias_type %r(double)i, "float"
|
692
|
+
|
693
|
+
m.register_type %r(^json)i, Type::Json.new
|
694
|
+
|
695
|
+
m.register_type(%r(decimal)i) do |sql_type|
|
696
|
+
scale = extract_scale(sql_type)
|
697
|
+
precision = extract_precision(sql_type)
|
698
|
+
|
699
|
+
if scale == 0
|
700
|
+
# FIXME: Remove this class as well
|
701
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
702
|
+
else
|
703
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
704
|
+
end
|
638
705
|
end
|
639
706
|
end
|
640
|
-
end
|
641
707
|
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
708
|
+
def register_class_with_limit(mapping, key, klass)
|
709
|
+
mapping.register_type(key) do |*args|
|
710
|
+
limit = extract_limit(args.last)
|
711
|
+
klass.new(limit: limit)
|
712
|
+
end
|
713
|
+
end
|
646
714
|
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
715
|
+
def register_class_with_precision(mapping, key, klass)
|
716
|
+
mapping.register_type(key) do |*args|
|
717
|
+
precision = extract_precision(args.last)
|
718
|
+
klass.new(precision: precision)
|
719
|
+
end
|
651
720
|
end
|
652
|
-
end
|
653
721
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
722
|
+
def extract_scale(sql_type)
|
723
|
+
case sql_type
|
724
|
+
when /\((\d+)\)/ then 0
|
725
|
+
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
726
|
+
end
|
658
727
|
end
|
659
|
-
end
|
660
728
|
|
661
|
-
|
662
|
-
|
663
|
-
when /\((\d+)\)/ then 0
|
664
|
-
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
729
|
+
def extract_precision(sql_type)
|
730
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
665
731
|
end
|
666
|
-
end
|
667
732
|
|
668
|
-
|
669
|
-
|
670
|
-
|
733
|
+
def extract_limit(sql_type)
|
734
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
671
739
|
|
672
|
-
|
673
|
-
|
740
|
+
private
|
741
|
+
def type_map
|
742
|
+
TYPE_MAP
|
674
743
|
end
|
675
744
|
|
676
745
|
def translate_exception_class(e, sql, binds)
|
@@ -683,7 +752,7 @@ module ActiveRecord
|
|
683
752
|
exception
|
684
753
|
end
|
685
754
|
|
686
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
|
755
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block) # :doc:
|
687
756
|
@instrumenter.instrument(
|
688
757
|
"sql.active_record",
|
689
758
|
sql: sql,
|
@@ -691,15 +760,21 @@ module ActiveRecord
|
|
691
760
|
binds: binds,
|
692
761
|
type_casted_binds: type_casted_binds,
|
693
762
|
statement_name: statement_name,
|
763
|
+
async: async,
|
694
764
|
connection: self) do
|
695
|
-
@lock.synchronize
|
696
|
-
yield
|
697
|
-
end
|
765
|
+
@lock.synchronize(&block)
|
698
766
|
rescue => e
|
699
767
|
raise translate_exception_class(e, sql, binds)
|
700
768
|
end
|
701
769
|
end
|
702
770
|
|
771
|
+
def transform_query(sql)
|
772
|
+
ActiveRecord.query_transformers.each do |transformer|
|
773
|
+
sql = transformer.call(sql)
|
774
|
+
end
|
775
|
+
sql
|
776
|
+
end
|
777
|
+
|
703
778
|
def translate_exception(exception, message:, sql:, binds:)
|
704
779
|
# override in derived class
|
705
780
|
case exception
|
@@ -31,6 +31,7 @@ module ActiveRecord
|
|
31
31
|
string: { name: "varchar", limit: 255 },
|
32
32
|
text: { name: "text" },
|
33
33
|
integer: { name: "int", limit: 4 },
|
34
|
+
bigint: { name: "bigint" },
|
34
35
|
float: { name: "float", limit: 24 },
|
35
36
|
decimal: { name: "decimal" },
|
36
37
|
datetime: { name: "datetime" },
|
@@ -54,7 +55,7 @@ module ActiveRecord
|
|
54
55
|
super(connection, logger, config)
|
55
56
|
end
|
56
57
|
|
57
|
-
def get_database_version
|
58
|
+
def get_database_version # :nodoc:
|
58
59
|
full_version_string = get_full_version
|
59
60
|
version_string = version_string(full_version_string)
|
60
61
|
Version.new(version_string, full_version_string)
|
@@ -137,6 +138,11 @@ module ActiveRecord
|
|
137
138
|
true
|
138
139
|
end
|
139
140
|
|
141
|
+
def field_ordered_value(column, values) # :nodoc:
|
142
|
+
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse])
|
143
|
+
Arel::Nodes::Descending.new(field)
|
144
|
+
end
|
145
|
+
|
140
146
|
def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
|
141
147
|
query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
|
142
148
|
end
|
@@ -174,7 +180,7 @@ module ActiveRecord
|
|
174
180
|
|
175
181
|
# REFERENTIAL INTEGRITY ====================================
|
176
182
|
|
177
|
-
def disable_referential_integrity
|
183
|
+
def disable_referential_integrity # :nodoc:
|
178
184
|
old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
|
179
185
|
|
180
186
|
begin
|
@@ -185,54 +191,40 @@ module ActiveRecord
|
|
185
191
|
end
|
186
192
|
end
|
187
193
|
|
188
|
-
# CONNECTION MANAGEMENT ====================================
|
189
|
-
|
190
|
-
def clear_cache! # :nodoc:
|
191
|
-
reload_type_map
|
192
|
-
super
|
193
|
-
end
|
194
|
-
|
195
194
|
#--
|
196
195
|
# DATABASE STATEMENTS ======================================
|
197
196
|
#++
|
198
197
|
|
199
198
|
# Executes the SQL statement in the context of this connection.
|
200
|
-
def execute(sql, name = nil)
|
201
|
-
|
202
|
-
mark_transaction_written_if_write(sql)
|
203
|
-
|
204
|
-
log(sql, name) do
|
205
|
-
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
206
|
-
@connection.query(sql)
|
207
|
-
end
|
208
|
-
end
|
199
|
+
def execute(sql, name = nil, async: false)
|
200
|
+
raw_execute(sql, name, async: async)
|
209
201
|
end
|
210
202
|
|
211
203
|
# Mysql2Adapter doesn't have to free a result after using it, but we use this method
|
212
204
|
# to write stuff in an abstract way without concerning ourselves about whether it
|
213
205
|
# needs to be explicitly freed or not.
|
214
|
-
def execute_and_free(sql, name = nil) # :nodoc:
|
215
|
-
yield execute(sql, name)
|
206
|
+
def execute_and_free(sql, name = nil, async: false) # :nodoc:
|
207
|
+
yield execute(sql, name, async: async)
|
216
208
|
end
|
217
209
|
|
218
|
-
def begin_db_transaction
|
210
|
+
def begin_db_transaction # :nodoc:
|
219
211
|
execute("BEGIN", "TRANSACTION")
|
220
212
|
end
|
221
213
|
|
222
|
-
def begin_isolated_db_transaction(isolation)
|
214
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
223
215
|
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
224
216
|
begin_db_transaction
|
225
217
|
end
|
226
218
|
|
227
|
-
def commit_db_transaction
|
219
|
+
def commit_db_transaction # :nodoc:
|
228
220
|
execute("COMMIT", "TRANSACTION")
|
229
221
|
end
|
230
222
|
|
231
|
-
def exec_rollback_db_transaction
|
223
|
+
def exec_rollback_db_transaction # :nodoc:
|
232
224
|
execute("ROLLBACK", "TRANSACTION")
|
233
225
|
end
|
234
226
|
|
235
|
-
def empty_insert_statement_value(primary_key = nil)
|
227
|
+
def empty_insert_statement_value(primary_key = nil) # :nodoc:
|
236
228
|
"VALUES ()"
|
237
229
|
end
|
238
230
|
|
@@ -270,7 +262,7 @@ module ActiveRecord
|
|
270
262
|
#
|
271
263
|
# Example:
|
272
264
|
# drop_database('sebastian_development')
|
273
|
-
def drop_database(name)
|
265
|
+
def drop_database(name) # :nodoc:
|
274
266
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
275
267
|
end
|
276
268
|
|
@@ -346,12 +338,12 @@ module ActiveRecord
|
|
346
338
|
end
|
347
339
|
end
|
348
340
|
|
349
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
341
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
350
342
|
default = extract_new_default_value(default_or_changes)
|
351
343
|
change_column table_name, column_name, nil, default: default
|
352
344
|
end
|
353
345
|
|
354
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
346
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
355
347
|
unless null || default.nil?
|
356
348
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
357
349
|
end
|
@@ -364,16 +356,16 @@ module ActiveRecord
|
|
364
356
|
change_column table_name, column_name, nil, comment: comment
|
365
357
|
end
|
366
358
|
|
367
|
-
def change_column(table_name, column_name, type, **options)
|
359
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
368
360
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
|
369
361
|
end
|
370
362
|
|
371
|
-
def rename_column(table_name, column_name, new_column_name)
|
363
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
372
364
|
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
|
373
365
|
rename_column_indexes(table_name, column_name, new_column_name)
|
374
366
|
end
|
375
367
|
|
376
|
-
def add_index(table_name, column_name, **options)
|
368
|
+
def add_index(table_name, column_name, **options) # :nodoc:
|
377
369
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
378
370
|
|
379
371
|
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
@@ -427,7 +419,7 @@ module ActiveRecord
|
|
427
419
|
if supports_check_constraints?
|
428
420
|
scope = quoted_scope(table_name)
|
429
421
|
|
430
|
-
|
422
|
+
sql = <<~SQL
|
431
423
|
SELECT cc.constraint_name AS 'name',
|
432
424
|
cc.check_clause AS 'expression'
|
433
425
|
FROM information_schema.check_constraints cc
|
@@ -437,6 +429,9 @@ module ActiveRecord
|
|
437
429
|
AND tc.table_name = #{scope[:name]}
|
438
430
|
AND cc.constraint_schema = #{scope[:schema]}
|
439
431
|
SQL
|
432
|
+
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
|
433
|
+
|
434
|
+
chk_info = exec_query(sql, "SCHEMA")
|
440
435
|
|
441
436
|
chk_info.map do |row|
|
442
437
|
options = {
|
@@ -548,8 +543,12 @@ module ActiveRecord
|
|
548
543
|
sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
|
549
544
|
elsif insert.update_duplicates?
|
550
545
|
sql << " ON DUPLICATE KEY UPDATE "
|
551
|
-
|
552
|
-
|
546
|
+
if insert.raw_update_sql?
|
547
|
+
sql << insert.raw_update_sql
|
548
|
+
else
|
549
|
+
sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
|
550
|
+
sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
|
551
|
+
end
|
553
552
|
end
|
554
553
|
|
555
554
|
sql
|
@@ -561,55 +560,77 @@ module ActiveRecord
|
|
561
560
|
end
|
562
561
|
end
|
563
562
|
|
564
|
-
|
565
|
-
|
566
|
-
|
563
|
+
class << self
|
564
|
+
private
|
565
|
+
def initialize_type_map(m)
|
566
|
+
super
|
567
567
|
|
568
|
-
|
569
|
-
|
570
|
-
|
568
|
+
m.register_type(%r(char)i) do |sql_type|
|
569
|
+
limit = extract_limit(sql_type)
|
570
|
+
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
571
|
+
end
|
572
|
+
|
573
|
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
|
574
|
+
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
|
575
|
+
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
|
576
|
+
m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
|
577
|
+
m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
|
578
|
+
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
|
579
|
+
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
|
580
|
+
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
|
581
|
+
m.register_type %r(^float)i, Type::Float.new(limit: 24)
|
582
|
+
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
+
|
584
|
+
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
+
register_integer_type m, %r(^int)i, limit: 4
|
586
|
+
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
+
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
+
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
+
|
590
|
+
m.alias_type %r(year)i, "integer"
|
591
|
+
m.alias_type %r(bit)i, "binary"
|
592
|
+
|
593
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
594
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
571
595
|
end
|
572
596
|
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
m.register_type %r(^double)i, Type::Float.new(limit: 53)
|
583
|
-
|
584
|
-
register_integer_type m, %r(^bigint)i, limit: 8
|
585
|
-
register_integer_type m, %r(^int)i, limit: 4
|
586
|
-
register_integer_type m, %r(^mediumint)i, limit: 3
|
587
|
-
register_integer_type m, %r(^smallint)i, limit: 2
|
588
|
-
register_integer_type m, %r(^tinyint)i, limit: 1
|
589
|
-
|
590
|
-
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
591
|
-
m.alias_type %r(year)i, "integer"
|
592
|
-
m.alias_type %r(bit)i, "binary"
|
593
|
-
|
594
|
-
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
595
|
-
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
596
|
-
end
|
597
|
+
def register_integer_type(mapping, key, **options)
|
598
|
+
mapping.register_type(key) do |sql_type|
|
599
|
+
if /\bunsigned\b/.match?(sql_type)
|
600
|
+
Type::UnsignedInteger.new(**options)
|
601
|
+
else
|
602
|
+
Type::Integer.new(**options)
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
597
606
|
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
Type::UnsignedInteger.new(**options)
|
607
|
+
def extract_precision(sql_type)
|
608
|
+
if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
|
609
|
+
super || 0
|
602
610
|
else
|
603
|
-
|
611
|
+
super
|
604
612
|
end
|
605
613
|
end
|
614
|
+
end
|
615
|
+
|
616
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
617
|
+
TYPE_MAP_WITH_BOOLEAN = Type::TypeMap.new(TYPE_MAP).tap do |m|
|
618
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
|
619
|
+
end
|
620
|
+
|
621
|
+
private
|
622
|
+
def type_map
|
623
|
+
emulate_booleans ? TYPE_MAP_WITH_BOOLEAN : TYPE_MAP
|
606
624
|
end
|
607
625
|
|
608
|
-
def
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
626
|
+
def raw_execute(sql, name, async: false)
|
627
|
+
materialize_transactions
|
628
|
+
mark_transaction_written_if_write(sql)
|
629
|
+
|
630
|
+
log(sql, name, async: async) do
|
631
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
632
|
+
@connection.query(sql)
|
633
|
+
end
|
613
634
|
end
|
614
635
|
end
|
615
636
|
|
@@ -780,14 +801,13 @@ module ActiveRecord
|
|
780
801
|
end
|
781
802
|
|
782
803
|
# Gather up all of the SET variables...
|
783
|
-
variable_assignments = variables.
|
804
|
+
variable_assignments = variables.filter_map do |k, v|
|
784
805
|
if defaults.include?(v)
|
785
806
|
"@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
|
786
807
|
elsif !v.nil?
|
787
808
|
"@@SESSION.#{k} = #{quote(v)}"
|
788
809
|
end
|
789
|
-
|
790
|
-
end.compact.join(", ")
|
810
|
+
end.join(", ")
|
791
811
|
|
792
812
|
# ...and send them all in one query
|
793
813
|
execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
|
@@ -839,10 +859,6 @@ module ActiveRecord
|
|
839
859
|
full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
|
840
860
|
end
|
841
861
|
|
842
|
-
# Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
|
843
|
-
# TODO: Remove the constant alias once Rails 6.1 has released.
|
844
|
-
MysqlString = Type::String # :nodoc:
|
845
|
-
|
846
862
|
ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
|
847
863
|
Type::ImmutableString.new(true: "1", false: "0", **args)
|
848
864
|
end
|