activerecord 6.1.7.10 → 7.0.0.alpha1
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 +726 -1404
- 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 +31 -9
- 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 +1 -1
- 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 +14 -23
- 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/preloader/association.rb +161 -47
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -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 +41 -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 +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +2 -14
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -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 +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
- 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 +28 -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 +6 -32
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +111 -125
- data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +17 -9
- data/lib/active_record/delegated_type.rb +33 -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 +29 -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 +80 -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 +41 -41
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- 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 +34 -5
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- 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/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +89 -10
- 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 -31
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +72 -48
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- 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 +39 -26
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +31 -22
- 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 +230 -49
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +8 -4
- data/lib/active_record/relation.rb +166 -77
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -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 +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +1 -6
- data/lib/active_record/tasks/database_tasks.rb +106 -22
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -13
- 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.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- 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 +3 -2
- data/lib/arel/predications.rb +1 -1
- 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 +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +43 -2
- data/lib/arel.rb +1 -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
- metadata +52 -14
@@ -59,17 +59,13 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# Returns an ActiveRecord::Result instance.
|
62
|
-
def select_all(arel, name = nil, binds = [], preparable: nil)
|
62
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
63
63
|
arel = arel_from_relation(arel)
|
64
64
|
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
65
65
|
|
66
|
-
|
67
|
-
select_prepared(sql, name, binds)
|
68
|
-
else
|
69
|
-
select(sql, name, binds)
|
70
|
-
end
|
66
|
+
select(sql, name, binds, prepare: prepared_statements && preparable, async: async && FutureResult::SelectAll)
|
71
67
|
rescue ::RangeError
|
72
|
-
ActiveRecord::Result.
|
68
|
+
ActiveRecord::Result.empty
|
73
69
|
end
|
74
70
|
|
75
71
|
# Returns a record hash with the column names as keys and column values
|
@@ -310,20 +306,20 @@ module ActiveRecord
|
|
310
306
|
#
|
311
307
|
# The mysql2 and postgresql adapters support setting the transaction
|
312
308
|
# isolation level.
|
313
|
-
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
309
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
|
314
310
|
if !requires_new && current_transaction.joinable?
|
315
311
|
if isolation
|
316
312
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
317
313
|
end
|
318
314
|
yield
|
319
315
|
else
|
320
|
-
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable)
|
316
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable, &block)
|
321
317
|
end
|
322
318
|
rescue ActiveRecord::Rollback
|
323
319
|
# rollbacks are silently swallowed
|
324
320
|
end
|
325
321
|
|
326
|
-
attr_reader :transaction_manager
|
322
|
+
attr_reader :transaction_manager # :nodoc:
|
327
323
|
|
328
324
|
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
329
325
|
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
@@ -340,7 +336,7 @@ module ActiveRecord
|
|
340
336
|
current_transaction.open?
|
341
337
|
end
|
342
338
|
|
343
|
-
def reset_transaction
|
339
|
+
def reset_transaction # :nodoc:
|
344
340
|
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
345
341
|
end
|
346
342
|
|
@@ -378,7 +374,7 @@ module ActiveRecord
|
|
378
374
|
exec_rollback_db_transaction
|
379
375
|
end
|
380
376
|
|
381
|
-
def exec_rollback_db_transaction() end
|
377
|
+
def exec_rollback_db_transaction() end # :nodoc:
|
382
378
|
|
383
379
|
def rollback_to_savepoint(name = nil)
|
384
380
|
exec_rollback_to_savepoint(name)
|
@@ -445,6 +441,19 @@ module ActiveRecord
|
|
445
441
|
end
|
446
442
|
end
|
447
443
|
|
444
|
+
# This is a safe default, even if not high precision on all databases
|
445
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
|
446
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
447
|
+
|
448
|
+
# Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
|
449
|
+
# arbitrary precision date/time columns.
|
450
|
+
#
|
451
|
+
# Adapters supporting datetime with precision should override this to
|
452
|
+
# provide as much precision as is available.
|
453
|
+
def high_precision_current_timestamp
|
454
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
455
|
+
end
|
456
|
+
|
448
457
|
private
|
449
458
|
def execute_batch(statements, name = nil)
|
450
459
|
statements.each do |statement|
|
@@ -481,8 +490,7 @@ module ActiveRecord
|
|
481
490
|
end
|
482
491
|
|
483
492
|
table = Arel::Table.new(table_name)
|
484
|
-
manager = Arel::InsertManager.new
|
485
|
-
manager.into(table)
|
493
|
+
manager = Arel::InsertManager.new(table)
|
486
494
|
|
487
495
|
if values_list.size == 1
|
488
496
|
values = values_list.shift
|
@@ -503,10 +511,10 @@ module ActiveRecord
|
|
503
511
|
end
|
504
512
|
|
505
513
|
def build_fixture_statements(fixture_set)
|
506
|
-
fixture_set.
|
514
|
+
fixture_set.filter_map do |table_name, fixtures|
|
507
515
|
next if fixtures.empty?
|
508
516
|
build_fixture_sql(fixtures, table_name)
|
509
|
-
end
|
517
|
+
end
|
510
518
|
end
|
511
519
|
|
512
520
|
def build_truncate_statement(table_name)
|
@@ -528,12 +536,28 @@ module ActiveRecord
|
|
528
536
|
end
|
529
537
|
|
530
538
|
# Returns an ActiveRecord::Result instance.
|
531
|
-
def select(sql, name = nil, binds = [])
|
532
|
-
|
533
|
-
|
539
|
+
def select(sql, name = nil, binds = [], prepare: false, async: false)
|
540
|
+
if async && async_enabled?
|
541
|
+
if current_transaction.joinable?
|
542
|
+
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
543
|
+
end
|
544
|
+
|
545
|
+
future_result = async.new(
|
546
|
+
pool,
|
547
|
+
sql,
|
548
|
+
name,
|
549
|
+
binds,
|
550
|
+
prepare: prepare,
|
551
|
+
)
|
552
|
+
if supports_concurrent_connections? && current_transaction.closed?
|
553
|
+
future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
|
554
|
+
else
|
555
|
+
future_result.execute!(self)
|
556
|
+
end
|
557
|
+
return future_result
|
558
|
+
end
|
534
559
|
|
535
|
-
|
536
|
-
exec_query(sql, name, binds, prepare: true)
|
560
|
+
exec_query(sql, name, binds, prepare: prepare)
|
537
561
|
end
|
538
562
|
|
539
563
|
def sql_for_insert(sql, pk, binds)
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters # :nodoc:
|
7
7
|
module QueryCache
|
8
8
|
class << self
|
9
|
-
def included(base)
|
9
|
+
def included(base) # :nodoc:
|
10
10
|
dirties_query_cache base, :create, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
11
|
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
12
12
|
|
@@ -93,18 +93,37 @@ module ActiveRecord
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def select_all(arel, name = nil, binds = [], preparable: nil)
|
97
|
-
|
98
|
-
|
96
|
+
def select_all(arel, name = nil, binds = [], preparable: nil, async: false)
|
97
|
+
arel = arel_from_relation(arel)
|
98
|
+
|
99
|
+
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch.
|
100
|
+
# Such queries should not be cached.
|
101
|
+
if @query_cache_enabled && !(arel.respond_to?(:locked) && arel.locked)
|
99
102
|
sql, binds, preparable = to_sql_and_binds(arel, binds, preparable)
|
100
103
|
|
101
|
-
|
104
|
+
if async
|
105
|
+
lookup_sql_cache(sql, name, binds) || super(sql, name, binds, preparable: preparable, async: async)
|
106
|
+
else
|
107
|
+
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable, async: async) }
|
108
|
+
end
|
102
109
|
else
|
103
110
|
super
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
107
114
|
private
|
115
|
+
def lookup_sql_cache(sql, name, binds)
|
116
|
+
@lock.synchronize do
|
117
|
+
if @query_cache[sql].key?(binds)
|
118
|
+
ActiveSupport::Notifications.instrument(
|
119
|
+
"sql.active_record",
|
120
|
+
cache_notification_info(sql, name, binds)
|
121
|
+
)
|
122
|
+
@query_cache[sql][binds]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
108
127
|
def cache_sql(sql, name, binds)
|
109
128
|
@lock.synchronize do
|
110
129
|
result =
|
@@ -134,13 +153,6 @@ module ActiveRecord
|
|
134
153
|
}
|
135
154
|
end
|
136
155
|
|
137
|
-
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
138
|
-
# queries should not be cached.
|
139
|
-
def locked?(arel)
|
140
|
-
arel = arel.arel if arel.is_a?(Relation)
|
141
|
-
arel.respond_to?(:locked) && arel.locked
|
142
|
-
end
|
143
|
-
|
144
156
|
def configure_query_cache!
|
145
157
|
enable_query_cache! if pool.query_cache_enabled
|
146
158
|
end
|
@@ -43,6 +43,13 @@ module ActiveRecord
|
|
43
43
|
_type_cast(value)
|
44
44
|
end
|
45
45
|
|
46
|
+
# Quote a value to be used as a bound parameter of unknown type. For example,
|
47
|
+
# MySQL might perform dangerous castings when comparing a string to a number,
|
48
|
+
# so this method will cast numbers to string.
|
49
|
+
def quote_bound_value(value)
|
50
|
+
_quote(value)
|
51
|
+
end
|
52
|
+
|
46
53
|
# If you are having to call this function, you are likely doing something
|
47
54
|
# wrong. The column does not have sufficient type information if the user
|
48
55
|
# provided a custom type on the class level either explicitly (via
|
@@ -59,7 +66,7 @@ module ActiveRecord
|
|
59
66
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
60
67
|
# characters.
|
61
68
|
def quote_string(s)
|
62
|
-
s.gsub(
|
69
|
+
s.gsub("\\", '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
63
70
|
end
|
64
71
|
|
65
72
|
# Quotes the column name. Defaults to no quoting.
|
@@ -113,10 +120,10 @@ module ActiveRecord
|
|
113
120
|
# if the value is a Time responding to usec.
|
114
121
|
def quoted_date(value)
|
115
122
|
if value.acts_like?(:time)
|
116
|
-
if ActiveRecord
|
117
|
-
value = value.getutc if
|
123
|
+
if ActiveRecord.default_timezone == :utc
|
124
|
+
value = value.getutc if !value.utc?
|
118
125
|
else
|
119
|
-
value = value.getlocal
|
126
|
+
value = value.getlocal
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
@@ -138,16 +145,7 @@ module ActiveRecord
|
|
138
145
|
end
|
139
146
|
|
140
147
|
def sanitize_as_sql_comment(value) # :nodoc:
|
141
|
-
|
142
|
-
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
143
|
-
# charcacters, possibly with single surrounding space.
|
144
|
-
# Then follows that by replacing any internal "*/" or "/ *" with
|
145
|
-
# "* /" or "/ *"
|
146
|
-
comment = value.to_s.dup
|
147
|
-
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
148
|
-
comment.gsub!("*/", "* /")
|
149
|
-
comment.gsub!("/*", "/ *")
|
150
|
-
comment
|
148
|
+
value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
151
149
|
end
|
152
150
|
|
153
151
|
def column_name_matcher # :nodoc:
|
@@ -14,8 +14,8 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
|
16
16
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
17
|
-
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
|
18
|
-
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
17
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?,
|
18
|
+
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
19
19
|
to: :@conn, private: true
|
20
20
|
|
21
21
|
private
|
@@ -52,11 +52,11 @@ module ActiveRecord
|
|
52
52
|
end
|
53
53
|
|
54
54
|
if supports_foreign_keys?
|
55
|
-
statements.concat(o.foreign_keys.map { |
|
55
|
+
statements.concat(o.foreign_keys.map { |fk| accept fk })
|
56
56
|
end
|
57
57
|
|
58
58
|
if supports_check_constraints?
|
59
|
-
statements.concat(o.check_constraints.map { |
|
59
|
+
statements.concat(o.check_constraints.map { |chk| accept chk })
|
60
60
|
end
|
61
61
|
|
62
62
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
@@ -159,19 +159,6 @@ module ActiveRecord
|
|
159
159
|
" TEMPORARY" if o.temporary
|
160
160
|
end
|
161
161
|
|
162
|
-
def foreign_key_in_create(from_table, to_table, options)
|
163
|
-
prefix = ActiveRecord::Base.table_name_prefix
|
164
|
-
suffix = ActiveRecord::Base.table_name_suffix
|
165
|
-
to_table = "#{prefix}#{to_table}#{suffix}"
|
166
|
-
options = foreign_key_options(from_table, to_table, options)
|
167
|
-
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
168
|
-
end
|
169
|
-
|
170
|
-
def check_constraint_in_create(table_name, expression, options)
|
171
|
-
options = check_constraint_options(table_name, expression, options)
|
172
|
-
accept CheckConstraintDefinition.new(table_name, expression, options)
|
173
|
-
end
|
174
|
-
|
175
162
|
def action_sql(action, dependency)
|
176
163
|
case dependency
|
177
164
|
when :nullify then "ON #{action} SET NULL"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
module ConnectionAdapters
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
5
|
# Abstract representation of an index definition on a table. Instances of
|
6
6
|
# this type are typically created and returned by methods in database
|
7
7
|
# adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
|
@@ -79,13 +79,13 @@ module ActiveRecord
|
|
79
79
|
|
80
80
|
AddColumnDefinition = Struct.new(:column) # :nodoc:
|
81
81
|
|
82
|
-
ChangeColumnDefinition = Struct.new(:column, :name)
|
82
|
+
ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
|
83
83
|
|
84
84
|
CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
|
85
85
|
|
86
86
|
PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
|
87
87
|
|
88
|
-
ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do
|
88
|
+
ForeignKeyDefinition = Struct.new(:from_table, :to_table, :options) do # :nodoc:
|
89
89
|
def name
|
90
90
|
options[:name]
|
91
91
|
end
|
@@ -198,10 +198,6 @@ module ActiveRecord
|
|
198
198
|
|
199
199
|
def index_options(table_name)
|
200
200
|
index_options = as_options(index)
|
201
|
-
|
202
|
-
# legacy reference index names are used on versions 6.0 and earlier
|
203
|
-
return index_options if options[:_uses_legacy_reference_index_name]
|
204
|
-
|
205
201
|
index_options[:name] ||= polymorphic_index_name(table_name) if polymorphic
|
206
202
|
index_options
|
207
203
|
end
|
@@ -257,6 +253,7 @@ module ActiveRecord
|
|
257
253
|
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
258
254
|
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
259
255
|
|
256
|
+
alias :blob :binary
|
260
257
|
alias :numeric :decimal
|
261
258
|
end
|
262
259
|
|
@@ -281,7 +278,7 @@ module ActiveRecord
|
|
281
278
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
282
279
|
# is actually of this type:
|
283
280
|
#
|
284
|
-
# class SomeMigration < ActiveRecord::Migration[
|
281
|
+
# class SomeMigration < ActiveRecord::Migration[7.0]
|
285
282
|
# def up
|
286
283
|
# create_table :foo do |t|
|
287
284
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
@@ -414,6 +411,12 @@ module ActiveRecord
|
|
414
411
|
end
|
415
412
|
end
|
416
413
|
|
414
|
+
if @conn.supports_datetime_with_precision?
|
415
|
+
if type == :datetime && !options.key?(:precision)
|
416
|
+
options[:precision] = 6
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
417
420
|
@columns_hash[name] = new_column_definition(name, type, **options)
|
418
421
|
|
419
422
|
if index
|
@@ -438,12 +441,12 @@ module ActiveRecord
|
|
438
441
|
indexes << [column_name, options]
|
439
442
|
end
|
440
443
|
|
441
|
-
def foreign_key(
|
442
|
-
foreign_keys <<
|
444
|
+
def foreign_key(to_table, **options)
|
445
|
+
foreign_keys << new_foreign_key_definition(to_table, options)
|
443
446
|
end
|
444
447
|
|
445
448
|
def check_constraint(expression, **options)
|
446
|
-
check_constraints <<
|
449
|
+
check_constraints << new_check_constraint_definition(expression, options)
|
447
450
|
end
|
448
451
|
|
449
452
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -485,6 +488,19 @@ module ActiveRecord
|
|
485
488
|
create_column_definition(name, type, options)
|
486
489
|
end
|
487
490
|
|
491
|
+
def new_foreign_key_definition(to_table, options) # :nodoc:
|
492
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
493
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
494
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
495
|
+
options = @conn.foreign_key_options(name, to_table, options)
|
496
|
+
ForeignKeyDefinition.new(name, to_table, options)
|
497
|
+
end
|
498
|
+
|
499
|
+
def new_check_constraint_definition(expression, options) # :nodoc:
|
500
|
+
options = @conn.check_constraint_options(name, expression, options)
|
501
|
+
CheckConstraintDefinition.new(name, expression, options)
|
502
|
+
end
|
503
|
+
|
488
504
|
private
|
489
505
|
def create_column_definition(name, type, options)
|
490
506
|
ColumnDefinition.new(name, type, options)
|
@@ -520,7 +536,7 @@ module ActiveRecord
|
|
520
536
|
def name; @td.name; end
|
521
537
|
|
522
538
|
def add_foreign_key(to_table, options)
|
523
|
-
@foreign_key_adds <<
|
539
|
+
@foreign_key_adds << @td.new_foreign_key_definition(to_table, options)
|
524
540
|
end
|
525
541
|
|
526
542
|
def drop_foreign_key(name)
|
@@ -528,7 +544,7 @@ module ActiveRecord
|
|
528
544
|
end
|
529
545
|
|
530
546
|
def add_check_constraint(expression, options)
|
531
|
-
@check_constraint_adds <<
|
547
|
+
@check_constraint_adds << @td.new_check_constraint_definition(expression, options)
|
532
548
|
end
|
533
549
|
|
534
550
|
def drop_check_constraint(constraint_name)
|
@@ -572,6 +588,7 @@ module ActiveRecord
|
|
572
588
|
# t.time
|
573
589
|
# t.date
|
574
590
|
# t.binary
|
591
|
+
# t.blob
|
575
592
|
# t.boolean
|
576
593
|
# t.foreign_key
|
577
594
|
# t.json
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/access"
|
4
|
-
require "
|
4
|
+
require "openssl"
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module ConnectionAdapters # :nodoc:
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
table_name[0...table_alias_length].tr(".", "_")
|
30
30
|
end
|
31
31
|
|
32
|
-
# Returns the relation names
|
32
|
+
# Returns the relation names usable to back Active Record models.
|
33
33
|
# For most adapters this means all #tables and #views.
|
34
34
|
def data_sources
|
35
35
|
query_values(data_source_sql, "SCHEMA")
|
@@ -518,24 +518,31 @@ module ActiveRecord
|
|
518
518
|
|
519
519
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
520
520
|
#
|
521
|
+
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
522
|
+
#
|
521
523
|
# The +type+ parameter is normally one of the migrations native types,
|
522
524
|
# which is one of the following:
|
523
525
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
524
526
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
525
527
|
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
526
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
528
|
+
# <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
|
527
529
|
#
|
528
530
|
# You may use a type not in this list as long as it is supported by your
|
529
531
|
# database (for example, "polygon" in MySQL), but this will not be database
|
530
532
|
# agnostic and should usually be avoided.
|
531
533
|
#
|
532
534
|
# Available options are (none of these exists by default):
|
535
|
+
# * <tt>:comment</tt> -
|
536
|
+
# Specifies the comment for the column. This option is ignored by some backends.
|
537
|
+
# * <tt>:collation</tt> -
|
538
|
+
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
|
539
|
+
# If not specified, the column will have the same collation as the table.
|
540
|
+
# * <tt>:default</tt> -
|
541
|
+
# The column's default value. Use +nil+ for +NULL+.
|
533
542
|
# * <tt>:limit</tt> -
|
534
543
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
535
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
544
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
|
536
545
|
# This option is ignored by some backends.
|
537
|
-
# * <tt>:default</tt> -
|
538
|
-
# The column's default value. Use +nil+ for +NULL+.
|
539
546
|
# * <tt>:null</tt> -
|
540
547
|
# Allows or disallows +NULL+ values in the column.
|
541
548
|
# * <tt>:precision</tt> -
|
@@ -604,7 +611,13 @@ module ActiveRecord
|
|
604
611
|
# # Ignores the method call if the column exists
|
605
612
|
# add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
|
606
613
|
def add_column(table_name, column_name, type, **options)
|
607
|
-
return if options[:if_not_exists] == true && column_exists?(table_name, column_name
|
614
|
+
return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
|
615
|
+
|
616
|
+
if supports_datetime_with_precision?
|
617
|
+
if type == :datetime && !options.key?(:precision)
|
618
|
+
options[:precision] = 6
|
619
|
+
end
|
620
|
+
end
|
608
621
|
|
609
622
|
at = create_alter_table table_name
|
610
623
|
at.add_column(column_name, type, **options)
|
@@ -629,9 +642,8 @@ module ActiveRecord
|
|
629
642
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
630
643
|
end
|
631
644
|
|
632
|
-
column_names
|
633
|
-
|
634
|
-
end
|
645
|
+
remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
|
646
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
|
635
647
|
end
|
636
648
|
|
637
649
|
# Removes the column from the table definition.
|
@@ -901,7 +913,7 @@ module ActiveRecord
|
|
901
913
|
remove_index(table_name, name: old_name)
|
902
914
|
end
|
903
915
|
|
904
|
-
def index_name(table_name, options)
|
916
|
+
def index_name(table_name, options) # :nodoc:
|
905
917
|
if Hash === options
|
906
918
|
if options[:column]
|
907
919
|
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
@@ -1027,6 +1039,10 @@ module ActiveRecord
|
|
1027
1039
|
#
|
1028
1040
|
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
1029
1041
|
#
|
1042
|
+
# ====== Creating a foreign key, ignoring method call if the foreign key exists
|
1043
|
+
#
|
1044
|
+
# add_foreign_key(:articles, :authors, if_not_exists: true)
|
1045
|
+
#
|
1030
1046
|
# ====== Creating a foreign key on a specific column
|
1031
1047
|
#
|
1032
1048
|
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
@@ -1054,10 +1070,14 @@ module ActiveRecord
|
|
1054
1070
|
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
1055
1071
|
# [<tt>:on_update</tt>]
|
1056
1072
|
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
1073
|
+
# [<tt>:if_not_exists</tt>]
|
1074
|
+
# Specifies if the foreign key already exists to not try to re-add it. This will avoid
|
1075
|
+
# duplicate column errors.
|
1057
1076
|
# [<tt>:validate</tt>]
|
1058
1077
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1059
1078
|
def add_foreign_key(from_table, to_table, **options)
|
1060
1079
|
return unless supports_foreign_keys?
|
1080
|
+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table)
|
1061
1081
|
|
1062
1082
|
options = foreign_key_options(from_table, to_table, options)
|
1063
1083
|
at = create_alter_table from_table
|
@@ -1087,12 +1107,18 @@ module ActiveRecord
|
|
1087
1107
|
#
|
1088
1108
|
# remove_foreign_key :accounts, name: :special_fk_name
|
1089
1109
|
#
|
1110
|
+
# Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
|
1111
|
+
# don't exist.
|
1112
|
+
#
|
1113
|
+
# remove_foreign_key :accounts, :branches, if_exists: true
|
1114
|
+
#
|
1090
1115
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
1091
1116
|
# with an addition of
|
1092
1117
|
# [<tt>:to_table</tt>]
|
1093
1118
|
# The name of the table that contains the referenced primary key.
|
1094
1119
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
1095
1120
|
return unless supports_foreign_keys?
|
1121
|
+
return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
|
1096
1122
|
|
1097
1123
|
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
1098
1124
|
|
@@ -1256,6 +1282,25 @@ module ActiveRecord
|
|
1256
1282
|
columns
|
1257
1283
|
end
|
1258
1284
|
|
1285
|
+
def distinct_relation_for_primary_key(relation) # :nodoc:
|
1286
|
+
values = columns_for_distinct(
|
1287
|
+
visitor.compile(relation.table[relation.primary_key]),
|
1288
|
+
relation.order_values
|
1289
|
+
)
|
1290
|
+
|
1291
|
+
limited = relation.reselect(values).distinct!
|
1292
|
+
limited_ids = select_rows(limited.arel, "SQL").map(&:last)
|
1293
|
+
|
1294
|
+
if limited_ids.empty?
|
1295
|
+
relation.none!
|
1296
|
+
else
|
1297
|
+
relation.where!(relation.primary_key => limited_ids)
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
relation.limit_value = relation.offset_value = nil
|
1301
|
+
relation
|
1302
|
+
end
|
1303
|
+
|
1259
1304
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
1260
1305
|
# Additional options (like +:null+) are forwarded to #add_column.
|
1261
1306
|
#
|
@@ -1277,11 +1322,10 @@ module ActiveRecord
|
|
1277
1322
|
# remove_timestamps(:suppliers)
|
1278
1323
|
#
|
1279
1324
|
def remove_timestamps(table_name, **options)
|
1280
|
-
|
1281
|
-
remove_column table_name, :created_at
|
1325
|
+
remove_columns table_name, :updated_at, :created_at
|
1282
1326
|
end
|
1283
1327
|
|
1284
|
-
def update_table_definition(table_name, base)
|
1328
|
+
def update_table_definition(table_name, base) # :nodoc:
|
1285
1329
|
Table.new(table_name, base)
|
1286
1330
|
end
|
1287
1331
|
|
@@ -1488,7 +1532,7 @@ module ActiveRecord
|
|
1488
1532
|
def foreign_key_name(table_name, options)
|
1489
1533
|
options.fetch(:name) do
|
1490
1534
|
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
1491
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1535
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1492
1536
|
|
1493
1537
|
"fk_rails_#{hashed_identifier}"
|
1494
1538
|
end
|
@@ -1516,7 +1560,7 @@ module ActiveRecord
|
|
1516
1560
|
options.fetch(:name) do
|
1517
1561
|
expression = options.fetch(:expression)
|
1518
1562
|
identifier = "#{table_name}_#{expression}_chk"
|
1519
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1563
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1520
1564
|
|
1521
1565
|
"chk_rails_#{hashed_identifier}"
|
1522
1566
|
end
|
@@ -73,7 +73,7 @@ module ActiveRecord
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
class NullTransaction
|
76
|
+
class NullTransaction # :nodoc:
|
77
77
|
def initialize; end
|
78
78
|
def state; end
|
79
79
|
def closed?; true; end
|
@@ -82,7 +82,7 @@ module ActiveRecord
|
|
82
82
|
def add_record(record, _ = true); end
|
83
83
|
end
|
84
84
|
|
85
|
-
class Transaction
|
85
|
+
class Transaction # :nodoc:
|
86
86
|
attr_reader :connection, :state, :savepoint_name, :isolation_level
|
87
87
|
attr_accessor :written
|
88
88
|
|
@@ -221,7 +221,7 @@ module ActiveRecord
|
|
221
221
|
end
|
222
222
|
end
|
223
223
|
|
224
|
-
class TransactionManager
|
224
|
+
class TransactionManager # :nodoc:
|
225
225
|
def initialize(connection)
|
226
226
|
@stack = []
|
227
227
|
@connection = connection
|