activerecord 5.2.0 → 5.2.8.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 +361 -0
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +25 -10
- data/lib/active_record/associations/belongs_to_association.rb +14 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb +11 -2
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -15
- data/lib/active_record/associations/collection_proxy.rb +8 -34
- data/lib/active_record/associations/has_many_association.rb +9 -0
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +8 -0
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -24
- data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
- data/lib/active_record/associations/join_dependency.rb +39 -64
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/associations/singular_association.rb +4 -10
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +9 -9
- data/lib/active_record/attribute_methods/dirty.rb +15 -10
- data/lib/active_record/attribute_methods/read.rb +1 -1
- data/lib/active_record/autosave_association.rb +27 -8
- data/lib/active_record/callbacks.rb +4 -0
- data/lib/active_record/coders/yaml_column.rb +13 -1
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +36 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +6 -15
- data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -6
- data/lib/active_record/core.rb +12 -1
- data/lib/active_record/counter_cache.rb +17 -13
- data/lib/active_record/enum.rb +1 -0
- data/lib/active_record/errors.rb +18 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/compatibility.rb +15 -15
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/persistence.rb +6 -5
- data/lib/active_record/query_cache.rb +4 -11
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +19 -3
- data/lib/active_record/reflection.rb +10 -14
- data/lib/active_record/relation/calculations.rb +16 -12
- data/lib/active_record/relation/delegation.rb +30 -0
- data/lib/active_record/relation/finder_methods.rb +10 -8
- data/lib/active_record/relation/merger.rb +10 -11
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +20 -14
- data/lib/active_record/relation/query_attribute.rb +5 -3
- data/lib/active_record/relation/query_methods.rb +50 -22
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation.rb +39 -20
- data/lib/active_record/scoping/default.rb +2 -2
- data/lib/active_record/scoping/named.rb +2 -0
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +1 -1
- data/lib/active_record/timestamp.rb +8 -1
- data/lib/active_record/transactions.rb +24 -21
- data/lib/active_record/type/serialized.rb +4 -0
- metadata +12 -13
@@ -272,7 +272,7 @@ module ActiveRecord
|
|
272
272
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
273
273
|
# unless the parent is/was a new record itself.
|
274
274
|
def associated_records_to_validate_or_save(association, new_record, autosave)
|
275
|
-
if new_record
|
275
|
+
if new_record || custom_validation_context?
|
276
276
|
association && association.target
|
277
277
|
elsif autosave
|
278
278
|
association.target.find_all(&:changed_for_autosave?)
|
@@ -304,7 +304,7 @@ module ActiveRecord
|
|
304
304
|
def validate_single_association(reflection)
|
305
305
|
association = association_instance_get(reflection.name)
|
306
306
|
record = association && association.reader
|
307
|
-
association_valid?(reflection, record) if record
|
307
|
+
association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
|
308
308
|
end
|
309
309
|
|
310
310
|
# Validate the associated records if <tt>:validate</tt> or
|
@@ -324,7 +324,7 @@ module ActiveRecord
|
|
324
324
|
def association_valid?(reflection, record, index = nil)
|
325
325
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
326
326
|
|
327
|
-
context = validation_context
|
327
|
+
context = validation_context if custom_validation_context?
|
328
328
|
|
329
329
|
unless valid = record.valid?(context)
|
330
330
|
if reflection.options[:autosave]
|
@@ -382,10 +382,14 @@ module ActiveRecord
|
|
382
382
|
if association = association_instance_get(reflection.name)
|
383
383
|
autosave = reflection.options[:autosave]
|
384
384
|
|
385
|
+
# By saving the instance variable in a local variable,
|
386
|
+
# we make the whole callback re-entrant.
|
387
|
+
new_record_before_save = @new_record_before_save
|
388
|
+
|
385
389
|
# reconstruct the scope now that we know the owner's id
|
386
390
|
association.reset_scope
|
387
391
|
|
388
|
-
if records = associated_records_to_validate_or_save(association,
|
392
|
+
if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
|
389
393
|
if autosave
|
390
394
|
records_to_destroy = records.select(&:marked_for_destruction?)
|
391
395
|
records_to_destroy.each { |record| association.destroy(record) }
|
@@ -397,11 +401,16 @@ module ActiveRecord
|
|
397
401
|
|
398
402
|
saved = true
|
399
403
|
|
400
|
-
if autosave != false && (
|
404
|
+
if autosave != false && (new_record_before_save || record.new_record?)
|
401
405
|
if autosave
|
402
406
|
saved = association.insert_record(record, false)
|
403
|
-
|
404
|
-
association.insert_record(record)
|
407
|
+
elsif !reflection.nested?
|
408
|
+
association_saved = association.insert_record(record)
|
409
|
+
|
410
|
+
if reflection.validate?
|
411
|
+
errors.add(reflection.name) unless association_saved
|
412
|
+
saved = association_saved
|
413
|
+
end
|
405
414
|
end
|
406
415
|
elsif autosave
|
407
416
|
saved = record.save(validate: false)
|
@@ -452,10 +461,16 @@ module ActiveRecord
|
|
452
461
|
# If the record is new or it has changed, returns true.
|
453
462
|
def record_changed?(reflection, record, key)
|
454
463
|
record.new_record? ||
|
455
|
-
|
464
|
+
association_foreign_key_changed?(reflection, record, key) ||
|
456
465
|
record.will_save_change_to_attribute?(reflection.foreign_key)
|
457
466
|
end
|
458
467
|
|
468
|
+
def association_foreign_key_changed?(reflection, record, key)
|
469
|
+
return false if reflection.through_reflection?
|
470
|
+
|
471
|
+
record.has_attribute?(reflection.foreign_key) && record[reflection.foreign_key] != key
|
472
|
+
end
|
473
|
+
|
459
474
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
460
475
|
#
|
461
476
|
# In addition, it will destroy the association if it was marked for destruction.
|
@@ -484,6 +499,10 @@ module ActiveRecord
|
|
484
499
|
end
|
485
500
|
end
|
486
501
|
|
502
|
+
def custom_validation_context?
|
503
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
504
|
+
end
|
505
|
+
|
487
506
|
def _ensure_no_duplicate_errors
|
488
507
|
errors.messages.each_key do |attribute|
|
489
508
|
errors[attribute].uniq!
|
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
def load(yaml)
|
24
24
|
return object_class.new if object_class != Object && yaml.nil?
|
25
25
|
return yaml unless yaml.is_a?(String) && /^---/.match?(yaml)
|
26
|
-
obj =
|
26
|
+
obj = yaml_load(yaml)
|
27
27
|
|
28
28
|
assert_valid_value(obj, action: "load")
|
29
29
|
obj ||= object_class.new if object_class != Object
|
@@ -45,6 +45,18 @@ module ActiveRecord
|
|
45
45
|
rescue ArgumentError
|
46
46
|
raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
|
47
47
|
end
|
48
|
+
|
49
|
+
def yaml_load(payload)
|
50
|
+
if !ActiveRecord::Base.use_yaml_unsafe_load
|
51
|
+
YAML.safe_load(payload, permitted_classes: ActiveRecord::Base.yaml_column_permitted_classes, aliases: true)
|
52
|
+
else
|
53
|
+
if YAML.respond_to?(:unsafe_load)
|
54
|
+
YAML.unsafe_load(payload)
|
55
|
+
else
|
56
|
+
YAML.load(payload)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
48
60
|
end
|
49
61
|
end
|
50
62
|
end
|
@@ -20,9 +20,9 @@ module ActiveRecord
|
|
20
20
|
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
|
21
21
|
|
22
22
|
if collection.has_limit_or_offset?
|
23
|
-
query = collection.select(column)
|
23
|
+
query = collection.select("#{column} AS collection_cache_key_timestamp")
|
24
24
|
subquery_alias = "subquery_for_cache_key"
|
25
|
-
subquery_column = "#{subquery_alias}
|
25
|
+
subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
|
26
26
|
subquery = query.arel.as(subquery_alias)
|
27
27
|
arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
|
28
28
|
else
|
@@ -188,7 +188,9 @@ module ActiveRecord
|
|
188
188
|
t0 = Time.now
|
189
189
|
elapsed = 0
|
190
190
|
loop do
|
191
|
-
|
191
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
192
|
+
@cond.wait(timeout - elapsed)
|
193
|
+
end
|
192
194
|
|
193
195
|
return remove if any?
|
194
196
|
|
@@ -308,7 +310,7 @@ module ActiveRecord
|
|
308
310
|
include QueryCache::ConnectionPoolConfiguration
|
309
311
|
|
310
312
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
311
|
-
attr_reader :spec, :
|
313
|
+
attr_reader :spec, :size, :reaper
|
312
314
|
|
313
315
|
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
|
314
316
|
# object which describes database connection information (e.g. adapter,
|
@@ -377,7 +379,7 @@ module ActiveRecord
|
|
377
379
|
# #connection can be called any number of times; the connection is
|
378
380
|
# held in a cache keyed by a thread.
|
379
381
|
def connection
|
380
|
-
@thread_cached_conns[connection_cache_key(
|
382
|
+
@thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
|
381
383
|
end
|
382
384
|
|
383
385
|
# Returns true if there is an open connection being used for the current thread.
|
@@ -386,7 +388,7 @@ module ActiveRecord
|
|
386
388
|
# #connection or #with_connection methods. Connections obtained through
|
387
389
|
# #checkout will not be detected by #active_connection?
|
388
390
|
def active_connection?
|
389
|
-
@thread_cached_conns[connection_cache_key(
|
391
|
+
@thread_cached_conns[connection_cache_key(current_thread)]
|
390
392
|
end
|
391
393
|
|
392
394
|
# Signal that the thread is finished with the current connection.
|
@@ -421,6 +423,21 @@ module ActiveRecord
|
|
421
423
|
synchronize { @connections.any? }
|
422
424
|
end
|
423
425
|
|
426
|
+
# Returns an array containing the connections currently in the pool.
|
427
|
+
# Access to the array does not require synchronization on the pool because
|
428
|
+
# the array is newly created and not retained by the pool.
|
429
|
+
#
|
430
|
+
# However; this method bypasses the ConnectionPool's thread-safe connection
|
431
|
+
# access pattern. A returned connection may be owned by another thread,
|
432
|
+
# unowned, or by happen-stance owned by the calling thread.
|
433
|
+
#
|
434
|
+
# Calling methods on a connection without ownership is subject to the
|
435
|
+
# thread-safety guarantees of the underlying method. Many of the methods
|
436
|
+
# on connection adapter classes are inherently multi-thread unsafe.
|
437
|
+
def connections
|
438
|
+
synchronize { @connections.dup }
|
439
|
+
end
|
440
|
+
|
424
441
|
# Disconnects all connections in the pool, and clears the pool.
|
425
442
|
#
|
426
443
|
# Raises:
|
@@ -666,6 +683,10 @@ module ActiveRecord
|
|
666
683
|
thread
|
667
684
|
end
|
668
685
|
|
686
|
+
def current_thread
|
687
|
+
@lock_thread || Thread.current
|
688
|
+
end
|
689
|
+
|
669
690
|
# Take control of all existing connections so a "group" action such as
|
670
691
|
# reload/disconnect can be performed safely. It is no longer enough to
|
671
692
|
# wrap it in +synchronize+ because some pool's actions are allowed
|
@@ -913,6 +934,16 @@ module ActiveRecord
|
|
913
934
|
# about the model. The model needs to pass a specification name to the handler,
|
914
935
|
# in order to look up the correct connection pool.
|
915
936
|
class ConnectionHandler
|
937
|
+
def self.create_owner_to_pool # :nodoc:
|
938
|
+
Concurrent::Map.new(initial_capacity: 2) do |h, k|
|
939
|
+
# Discard the parent's connection pools immediately; we have no need
|
940
|
+
# of them
|
941
|
+
discard_unowned_pools(h)
|
942
|
+
|
943
|
+
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
944
|
+
end
|
945
|
+
end
|
946
|
+
|
916
947
|
def self.unowned_pool_finalizer(pid_map) # :nodoc:
|
917
948
|
lambda do |_|
|
918
949
|
discard_unowned_pools(pid_map)
|
@@ -927,13 +958,7 @@ module ActiveRecord
|
|
927
958
|
|
928
959
|
def initialize
|
929
960
|
# These caches are keyed by spec.name (ConnectionSpecification#name).
|
930
|
-
@owner_to_pool =
|
931
|
-
# Discard the parent's connection pools immediately; we have no need
|
932
|
-
# of them
|
933
|
-
ConnectionHandler.discard_unowned_pools(h)
|
934
|
-
|
935
|
-
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
936
|
-
end
|
961
|
+
@owner_to_pool = ConnectionHandler.create_owner_to_pool
|
937
962
|
|
938
963
|
# Backup finalizer: if the forked child never needed a pool, the above
|
939
964
|
# early discard has not occurred
|
@@ -20,9 +20,22 @@ module ActiveRecord
|
|
20
20
|
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
21
|
"The values must be stored on the AST directly"
|
22
22
|
end
|
23
|
-
|
24
|
-
|
23
|
+
|
24
|
+
if prepared_statements
|
25
|
+
sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
|
26
|
+
|
27
|
+
if binds.length > bind_params_length
|
28
|
+
unprepared_statement do
|
29
|
+
sql, binds = to_sql_and_binds(arel_or_sql_string)
|
30
|
+
visitor.preparable = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
sql = visitor.accept(arel_or_sql_string.ast, collector).value
|
35
|
+
end
|
36
|
+
[sql.freeze, binds]
|
25
37
|
else
|
38
|
+
visitor.preparable = false if prepared_statements
|
26
39
|
[arel_or_sql_string.dup.freeze, binds]
|
27
40
|
end
|
28
41
|
end
|
@@ -46,11 +59,11 @@ module ActiveRecord
|
|
46
59
|
def select_all(arel, name = nil, binds = [], preparable: nil)
|
47
60
|
arel = arel_from_relation(arel)
|
48
61
|
sql, binds = to_sql_and_binds(arel, binds)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
preparable = visitor.preparable
|
62
|
+
|
63
|
+
if preparable.nil?
|
64
|
+
preparable = prepared_statements ? visitor.preparable : false
|
53
65
|
end
|
66
|
+
|
54
67
|
if prepared_statements && preparable
|
55
68
|
select_prepared(sql, name, binds)
|
56
69
|
else
|
@@ -32,17 +32,17 @@ module ActiveRecord
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def enable_query_cache!
|
35
|
-
@query_cache_enabled[connection_cache_key(
|
35
|
+
@query_cache_enabled[connection_cache_key(current_thread)] = true
|
36
36
|
connection.enable_query_cache! if active_connection?
|
37
37
|
end
|
38
38
|
|
39
39
|
def disable_query_cache!
|
40
|
-
@query_cache_enabled.delete connection_cache_key(
|
40
|
+
@query_cache_enabled.delete connection_cache_key(current_thread)
|
41
41
|
connection.disable_query_cache! if active_connection?
|
42
42
|
end
|
43
43
|
|
44
44
|
def query_cache_enabled
|
45
|
-
@query_cache_enabled[connection_cache_key(
|
45
|
+
@query_cache_enabled[connection_cache_key(current_thread)]
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -96,6 +96,11 @@ module ActiveRecord
|
|
96
96
|
if @query_cache_enabled && !locked?(arel)
|
97
97
|
arel = arel_from_relation(arel)
|
98
98
|
sql, binds = to_sql_and_binds(arel, binds)
|
99
|
+
|
100
|
+
if preparable.nil?
|
101
|
+
preparable = prepared_statements ? visitor.preparable : false
|
102
|
+
end
|
103
|
+
|
99
104
|
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
|
100
105
|
else
|
101
106
|
super
|
@@ -498,6 +498,9 @@ module ActiveRecord
|
|
498
498
|
# t.date
|
499
499
|
# t.binary
|
500
500
|
# t.boolean
|
501
|
+
# t.foreign_key
|
502
|
+
# t.json
|
503
|
+
# t.virtual
|
501
504
|
# t.remove
|
502
505
|
# t.remove_references
|
503
506
|
# t.remove_belongs_to
|
@@ -662,19 +665,19 @@ module ActiveRecord
|
|
662
665
|
|
663
666
|
# Adds a foreign key.
|
664
667
|
#
|
665
|
-
#
|
668
|
+
# t.foreign_key(:authors)
|
666
669
|
#
|
667
670
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
668
|
-
def foreign_key(*args)
|
671
|
+
def foreign_key(*args)
|
669
672
|
@base.add_foreign_key(name, *args)
|
670
673
|
end
|
671
674
|
|
672
675
|
# Checks to see if a foreign key exists.
|
673
676
|
#
|
674
|
-
#
|
677
|
+
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
675
678
|
#
|
676
679
|
# See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
|
677
|
-
def foreign_key_exists?(*args)
|
680
|
+
def foreign_key_exists?(*args)
|
678
681
|
@base.foreign_key_exists?(name, *args)
|
679
682
|
end
|
680
683
|
end
|
@@ -100,7 +100,7 @@ module ActiveRecord
|
|
100
100
|
def index_exists?(table_name, column_name, options = {})
|
101
101
|
column_names = Array(column_name).map(&:to_s)
|
102
102
|
checks = []
|
103
|
-
checks << lambda { |i| i.columns == column_names }
|
103
|
+
checks << lambda { |i| Array(i.columns) == column_names }
|
104
104
|
checks << lambda { |i| i.unique } if options[:unique]
|
105
105
|
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
106
106
|
|
@@ -305,7 +305,7 @@ module ActiveRecord
|
|
305
305
|
yield td if block_given?
|
306
306
|
|
307
307
|
if options[:force]
|
308
|
-
drop_table(table_name,
|
308
|
+
drop_table(table_name, options.merge(if_exists: true))
|
309
309
|
end
|
310
310
|
|
311
311
|
result = execute schema_creation.accept td
|
@@ -741,22 +741,13 @@ module ActiveRecord
|
|
741
741
|
# ====== Creating an index with a specific operator class
|
742
742
|
#
|
743
743
|
# add_index(:developers, :name, using: 'gist', opclass: :gist_trgm_ops)
|
744
|
-
#
|
745
|
-
# generates:
|
746
|
-
#
|
747
|
-
# CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
|
744
|
+
# # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
|
748
745
|
#
|
749
746
|
# add_index(:developers, [:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
|
750
|
-
#
|
751
|
-
# generates:
|
752
|
-
#
|
753
|
-
# CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
|
747
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
|
754
748
|
#
|
755
749
|
# add_index(:developers, [:name, :city], using: 'gist', opclass: :gist_trgm_ops)
|
756
|
-
#
|
757
|
-
# generates:
|
758
|
-
#
|
759
|
-
# CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
|
750
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
|
760
751
|
#
|
761
752
|
# Note: only supported by PostgreSQL
|
762
753
|
#
|
@@ -908,7 +899,7 @@ module ActiveRecord
|
|
908
899
|
foreign_key_options = { to_table: reference_name }
|
909
900
|
end
|
910
901
|
foreign_key_options[:column] ||= "#{ref_name}_id"
|
911
|
-
remove_foreign_key(table_name,
|
902
|
+
remove_foreign_key(table_name, foreign_key_options)
|
912
903
|
end
|
913
904
|
|
914
905
|
remove_column(table_name, "#{ref_name}_id")
|
@@ -17,11 +17,19 @@ module ActiveRecord
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def committed?
|
20
|
-
@state == :committed
|
20
|
+
@state == :committed || @state == :fully_committed
|
21
|
+
end
|
22
|
+
|
23
|
+
def fully_committed?
|
24
|
+
@state == :fully_committed
|
21
25
|
end
|
22
26
|
|
23
27
|
def rolledback?
|
24
|
-
@state == :rolledback
|
28
|
+
@state == :rolledback || @state == :fully_rolledback
|
29
|
+
end
|
30
|
+
|
31
|
+
def fully_rolledback?
|
32
|
+
@state == :fully_rolledback
|
25
33
|
end
|
26
34
|
|
27
35
|
def fully_completed?
|
@@ -55,10 +63,19 @@ module ActiveRecord
|
|
55
63
|
@state = :rolledback
|
56
64
|
end
|
57
65
|
|
66
|
+
def full_rollback!
|
67
|
+
@children.each { |c| c.rollback! }
|
68
|
+
@state = :fully_rolledback
|
69
|
+
end
|
70
|
+
|
58
71
|
def commit!
|
59
72
|
@state = :committed
|
60
73
|
end
|
61
74
|
|
75
|
+
def full_commit!
|
76
|
+
@state = :fully_committed
|
77
|
+
end
|
78
|
+
|
62
79
|
def nullify!
|
63
80
|
@state = nil
|
64
81
|
end
|
@@ -89,10 +106,6 @@ module ActiveRecord
|
|
89
106
|
records << record
|
90
107
|
end
|
91
108
|
|
92
|
-
def rollback
|
93
|
-
@state.rollback!
|
94
|
-
end
|
95
|
-
|
96
109
|
def rollback_records
|
97
110
|
ite = records.uniq
|
98
111
|
while record = ite.shift
|
@@ -104,10 +117,6 @@ module ActiveRecord
|
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
107
|
-
def commit
|
108
|
-
@state.commit!
|
109
|
-
end
|
110
|
-
|
111
120
|
def before_commit_records
|
112
121
|
records.uniq.each(&:before_committed!) if @run_commit_callbacks
|
113
122
|
end
|
@@ -146,12 +155,12 @@ module ActiveRecord
|
|
146
155
|
|
147
156
|
def rollback
|
148
157
|
connection.rollback_to_savepoint(savepoint_name)
|
149
|
-
|
158
|
+
@state.rollback!
|
150
159
|
end
|
151
160
|
|
152
161
|
def commit
|
153
162
|
connection.release_savepoint(savepoint_name)
|
154
|
-
|
163
|
+
@state.commit!
|
155
164
|
end
|
156
165
|
|
157
166
|
def full_rollback?; false; end
|
@@ -169,12 +178,12 @@ module ActiveRecord
|
|
169
178
|
|
170
179
|
def rollback
|
171
180
|
connection.rollback_db_transaction
|
172
|
-
|
181
|
+
@state.full_rollback!
|
173
182
|
end
|
174
183
|
|
175
184
|
def commit
|
176
185
|
connection.commit_db_transaction
|
177
|
-
|
186
|
+
@state.full_commit!
|
178
187
|
end
|
179
188
|
end
|
180
189
|
|
@@ -560,17 +560,6 @@ module ActiveRecord
|
|
560
560
|
@max_allowed_packet ||= (show_variable("max_allowed_packet") - bytes_margin)
|
561
561
|
end
|
562
562
|
|
563
|
-
def with_multi_statements
|
564
|
-
previous_flags = @config[:flags]
|
565
|
-
@config[:flags] = Mysql2::Client::MULTI_STATEMENTS
|
566
|
-
reconnect!
|
567
|
-
|
568
|
-
yield
|
569
|
-
ensure
|
570
|
-
@config[:flags] = previous_flags
|
571
|
-
reconnect!
|
572
|
-
end
|
573
|
-
|
574
563
|
def initialize_type_map(m = type_map)
|
575
564
|
super
|
576
565
|
|
@@ -815,15 +804,25 @@ module ActiveRecord
|
|
815
804
|
end
|
816
805
|
|
817
806
|
def mismatched_foreign_key(message)
|
818
|
-
|
819
|
-
|
820
|
-
|
807
|
+
match = %r/
|
808
|
+
(?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
|
809
|
+
FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
|
810
|
+
REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
|
811
|
+
/xmi.match(message)
|
812
|
+
|
813
|
+
options = {
|
821
814
|
message: message,
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
815
|
+
}
|
816
|
+
|
817
|
+
if match
|
818
|
+
options[:table] = match[:table]
|
819
|
+
options[:foreign_key] = match[:foreign_key]
|
820
|
+
options[:target_table] = match[:target_table]
|
821
|
+
options[:primary_key] = match[:primary_key]
|
822
|
+
options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
|
823
|
+
end
|
824
|
+
|
825
|
+
MismatchedForeignKey.new(options)
|
827
826
|
end
|
828
827
|
|
829
828
|
def integer_to_sql(limit) # :nodoc:
|
@@ -195,12 +195,12 @@ module ActiveRecord
|
|
195
195
|
if e.path == path_to_adapter
|
196
196
|
# We can assume that a non-builtin adapter was specified, so it's
|
197
197
|
# either misspelled or missing from Gemfile.
|
198
|
-
raise
|
198
|
+
raise LoadError, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
|
199
199
|
|
200
200
|
# Bubbled up from the adapter require. Prefix the exception message
|
201
201
|
# with some guidance about how to address it and reraise.
|
202
202
|
else
|
203
|
-
raise
|
203
|
+
raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
@@ -3,15 +3,24 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
5
|
module DetermineIfPreparableVisitor
|
6
|
-
|
6
|
+
attr_accessor :preparable
|
7
7
|
|
8
8
|
def accept(*)
|
9
9
|
@preparable = true
|
10
10
|
super
|
11
11
|
end
|
12
12
|
|
13
|
-
def visit_Arel_Nodes_In(
|
13
|
+
def visit_Arel_Nodes_In(o, collector)
|
14
14
|
@preparable = false
|
15
|
+
|
16
|
+
if Array === o.right && !o.right.empty?
|
17
|
+
o.right.delete_if do |bind|
|
18
|
+
if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
|
19
|
+
!bind.value.boundable?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
super
|
16
25
|
end
|
17
26
|
|
@@ -62,6 +62,42 @@ module ActiveRecord
|
|
62
62
|
@connection.next_result while @connection.more_results?
|
63
63
|
end
|
64
64
|
|
65
|
+
def supports_set_server_option?
|
66
|
+
@connection.respond_to?(:set_server_option)
|
67
|
+
end
|
68
|
+
|
69
|
+
def multi_statements_enabled?(flags)
|
70
|
+
if flags.is_a?(Array)
|
71
|
+
flags.include?("MULTI_STATEMENTS")
|
72
|
+
else
|
73
|
+
(flags & Mysql2::Client::MULTI_STATEMENTS) != 0
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def with_multi_statements
|
78
|
+
previous_flags = @config[:flags]
|
79
|
+
|
80
|
+
unless multi_statements_enabled?(previous_flags)
|
81
|
+
if supports_set_server_option?
|
82
|
+
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
83
|
+
else
|
84
|
+
@config[:flags] = Mysql2::Client::MULTI_STATEMENTS
|
85
|
+
reconnect!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
unless multi_statements_enabled?(previous_flags)
|
92
|
+
if supports_set_server_option?
|
93
|
+
@connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
94
|
+
else
|
95
|
+
@config[:flags] = previous_flags
|
96
|
+
reconnect!
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
65
101
|
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
66
102
|
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
67
103
|
# made since we established the connection
|