activerecord 5.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +218 -2
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +22 -17
- data/lib/active_record/associations/collection_proxy.rb +20 -7
- data/lib/active_record/associations/has_many_through_association.rb +4 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/preloader/association.rb +18 -4
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations.rb +5 -0
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_set/builder.rb +29 -7
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +40 -32
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +38 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -45
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +6 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -5
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -2
- data/lib/active_record/core.rb +3 -1
- data/lib/active_record/enum.rb +6 -5
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/migration.rb +6 -5
- data/lib/active_record/model_schema.rb +134 -47
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +10 -4
- data/lib/active_record/query_cache.rb +13 -15
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/reflection.rb +12 -0
- data/lib/active_record/relation/calculations.rb +11 -11
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +11 -9
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/relation.rb +7 -4
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/named.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- data/lib/active_record.rb +1 -1
- metadata +8 -7
|
@@ -95,7 +95,8 @@ module ActiveRecord
|
|
|
95
95
|
base_name.foreign_key
|
|
96
96
|
else
|
|
97
97
|
if ActiveRecord::Base != self && table_exists?
|
|
98
|
-
connection.schema_cache.primary_keys(table_name)
|
|
98
|
+
pk = connection.schema_cache.primary_keys(table_name)
|
|
99
|
+
suppress_composite_primary_key(pk)
|
|
99
100
|
else
|
|
100
101
|
'id'
|
|
101
102
|
end
|
|
@@ -122,6 +123,18 @@ module ActiveRecord
|
|
|
122
123
|
@quoted_primary_key = nil
|
|
123
124
|
@attributes_builder = nil
|
|
124
125
|
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def suppress_composite_primary_key(pk)
|
|
130
|
+
return pk unless pk.is_a?(Array)
|
|
131
|
+
|
|
132
|
+
warn <<-WARNING.strip_heredoc
|
|
133
|
+
WARNING: Active Record does not support composite primary key.
|
|
134
|
+
|
|
135
|
+
#{table_name} has composite primary key. Composite primary key is ignored.
|
|
136
|
+
WARNING
|
|
137
|
+
end
|
|
125
138
|
end
|
|
126
139
|
end
|
|
127
140
|
end
|
|
@@ -279,9 +279,8 @@ module ActiveRecord
|
|
|
279
279
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
|
280
280
|
# attribute +attr_name+. String attributes are truncated up to 50
|
|
281
281
|
# characters, Date and Time attributes are returned in the
|
|
282
|
-
# <tt>:db</tt> format
|
|
283
|
-
#
|
|
284
|
-
# modification.
|
|
282
|
+
# <tt>:db</tt> format. Other attributes return the value of
|
|
283
|
+
# <tt>#inspect</tt> without modification.
|
|
285
284
|
#
|
|
286
285
|
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
|
|
287
286
|
#
|
|
@@ -292,7 +291,7 @@ module ActiveRecord
|
|
|
292
291
|
# # => "\"2012-10-22 00:15:07\""
|
|
293
292
|
#
|
|
294
293
|
# person.attribute_for_inspect(:tag_ids)
|
|
295
|
-
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
294
|
+
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
|
296
295
|
def attribute_for_inspect(attr_name)
|
|
297
296
|
value = read_attribute(attr_name)
|
|
298
297
|
|
|
@@ -300,9 +299,6 @@ module ActiveRecord
|
|
|
300
299
|
"#{value[0, 50]}...".inspect
|
|
301
300
|
elsif value.is_a?(Date) || value.is_a?(Time)
|
|
302
301
|
%("#{value.to_s(:db)}")
|
|
303
|
-
elsif value.is_a?(Array) && value.size > 10
|
|
304
|
-
inspected = value.first(10).inspect
|
|
305
|
-
%(#{inspected[0...-1]}, ...])
|
|
306
302
|
else
|
|
307
303
|
value.inspect
|
|
308
304
|
end
|
|
@@ -3,11 +3,12 @@ require 'active_record/attribute'
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
class AttributeSet # :nodoc:
|
|
5
5
|
class Builder # :nodoc:
|
|
6
|
-
attr_reader :types, :always_initialized
|
|
6
|
+
attr_reader :types, :always_initialized, :default
|
|
7
7
|
|
|
8
|
-
def initialize(types, always_initialized = nil)
|
|
8
|
+
def initialize(types, always_initialized = nil, &default)
|
|
9
9
|
@types = types
|
|
10
10
|
@always_initialized = always_initialized
|
|
11
|
+
@default = default
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def build_from_database(values = {}, additional_types = {})
|
|
@@ -15,21 +16,22 @@ module ActiveRecord
|
|
|
15
16
|
values[always_initialized] = nil
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
attributes = LazyAttributeHash.new(types, values, additional_types)
|
|
19
|
+
attributes = LazyAttributeHash.new(types, values, additional_types, &default)
|
|
19
20
|
AttributeSet.new(attributes)
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
class LazyAttributeHash # :nodoc:
|
|
25
|
-
delegate :transform_values, :each_key, to: :materialize
|
|
26
|
+
delegate :transform_values, :each_key, :fetch, to: :materialize
|
|
26
27
|
|
|
27
|
-
def initialize(types, values, additional_types)
|
|
28
|
+
def initialize(types, values, additional_types, &default)
|
|
28
29
|
@types = types
|
|
29
30
|
@values = values
|
|
30
31
|
@additional_types = additional_types
|
|
31
32
|
@materialized = false
|
|
32
33
|
@delegate_hash = {}
|
|
34
|
+
@default = default || proc {}
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def key?(key)
|
|
@@ -76,9 +78,29 @@ module ActiveRecord
|
|
|
76
78
|
end
|
|
77
79
|
end
|
|
78
80
|
|
|
81
|
+
def marshal_dump
|
|
82
|
+
materialize
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def marshal_load(delegate_hash)
|
|
86
|
+
@delegate_hash = delegate_hash
|
|
87
|
+
@types = {}
|
|
88
|
+
@values = {}
|
|
89
|
+
@additional_types = {}
|
|
90
|
+
@materialized = true
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def encode_with(coder)
|
|
94
|
+
coder["delegate_hash"] = materialize
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def init_with(coder)
|
|
98
|
+
marshal_load(coder["delegate_hash"])
|
|
99
|
+
end
|
|
100
|
+
|
|
79
101
|
protected
|
|
80
102
|
|
|
81
|
-
attr_reader :types, :values, :additional_types, :delegate_hash
|
|
103
|
+
attr_reader :types, :values, :additional_types, :delegate_hash, :default
|
|
82
104
|
|
|
83
105
|
def materialize
|
|
84
106
|
unless @materialized
|
|
@@ -101,7 +123,7 @@ module ActiveRecord
|
|
|
101
123
|
if value_present
|
|
102
124
|
delegate_hash[name] = Attribute.from_database(name, value, type)
|
|
103
125
|
elsif types.key?(name)
|
|
104
|
-
delegate_hash[name] = Attribute.uninitialized(name, type)
|
|
126
|
+
delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
|
|
105
127
|
end
|
|
106
128
|
end
|
|
107
129
|
end
|
|
@@ -34,10 +34,10 @@ module ActiveRecord
|
|
|
34
34
|
# is not passed, the previous default value (if any) will be used.
|
|
35
35
|
# Otherwise, the default will be +nil+.
|
|
36
36
|
#
|
|
37
|
-
# +array+ (
|
|
37
|
+
# +array+ (PostgreSQL only) specifies that the type should be an array (see the
|
|
38
38
|
# examples below).
|
|
39
39
|
#
|
|
40
|
-
# +range+ (
|
|
40
|
+
# +range+ (PostgreSQL only) specifies that the type should be a range (see the
|
|
41
41
|
# examples below).
|
|
42
42
|
#
|
|
43
43
|
# ==== Examples
|
|
@@ -253,7 +253,7 @@ module ActiveRecord
|
|
|
253
253
|
name,
|
|
254
254
|
value,
|
|
255
255
|
type,
|
|
256
|
-
_default_attributes
|
|
256
|
+
_default_attributes.fetch(name.to_s) { nil },
|
|
257
257
|
)
|
|
258
258
|
else
|
|
259
259
|
default_attribute = Attribute.from_database(name, value, type)
|
|
@@ -329,26 +329,20 @@ module ActiveRecord
|
|
|
329
329
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
|
330
330
|
|
|
331
331
|
validation_context = self.validation_context unless [:create, :update].include?(self.validation_context)
|
|
332
|
+
|
|
332
333
|
unless valid = record.valid?(validation_context)
|
|
333
334
|
if reflection.options[:autosave]
|
|
334
335
|
indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
|
|
335
336
|
|
|
336
337
|
record.errors.each do |attribute, message|
|
|
337
|
-
|
|
338
|
-
attribute = "#{reflection.name}[#{index}].#{attribute}"
|
|
339
|
-
else
|
|
340
|
-
attribute = "#{reflection.name}.#{attribute}"
|
|
341
|
-
end
|
|
338
|
+
attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
|
342
339
|
errors[attribute] << message
|
|
343
340
|
errors[attribute].uniq!
|
|
344
341
|
end
|
|
345
342
|
|
|
346
343
|
record.errors.details.each_key do |attribute|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
else
|
|
350
|
-
reflection_attribute = "#{reflection.name}.#{attribute}"
|
|
351
|
-
end
|
|
344
|
+
reflection_attribute =
|
|
345
|
+
normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym
|
|
352
346
|
|
|
353
347
|
record.errors.details[attribute].each do |error|
|
|
354
348
|
errors.details[reflection_attribute] << error
|
|
@@ -362,6 +356,14 @@ module ActiveRecord
|
|
|
362
356
|
valid
|
|
363
357
|
end
|
|
364
358
|
|
|
359
|
+
def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
|
360
|
+
if indexed_attribute
|
|
361
|
+
"#{reflection.name}[#{index}].#{attribute}"
|
|
362
|
+
else
|
|
363
|
+
"#{reflection.name}.#{attribute}"
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
365
367
|
# Is used as a before_save callback to check while saving a collection
|
|
366
368
|
# association whether or not the parent was a new record before saving.
|
|
367
369
|
def before_save_collection_association
|
|
@@ -457,7 +459,9 @@ module ActiveRecord
|
|
|
457
459
|
# In addition, it will destroy the association if it was marked for destruction.
|
|
458
460
|
def save_belongs_to_association(reflection)
|
|
459
461
|
association = association_instance_get(reflection.name)
|
|
460
|
-
|
|
462
|
+
return unless association && association.loaded? && !association.stale_target?
|
|
463
|
+
|
|
464
|
+
record = association.load_target
|
|
461
465
|
if record && !record.destroyed?
|
|
462
466
|
autosave = reflection.options[:autosave]
|
|
463
467
|
|
data/lib/active_record/base.rb
CHANGED
|
@@ -307,6 +307,7 @@ module ActiveRecord
|
|
|
307
307
|
end
|
|
308
308
|
|
|
309
309
|
include MonitorMixin
|
|
310
|
+
include QueryCache::ConnectionPoolConfiguration
|
|
310
311
|
|
|
311
312
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
|
312
313
|
attr_reader :spec, :connections, :size, :reaper
|
|
@@ -349,8 +350,7 @@ module ActiveRecord
|
|
|
349
350
|
# currently in the process of independently establishing connections to the DB.
|
|
350
351
|
@now_connecting = 0
|
|
351
352
|
|
|
352
|
-
|
|
353
|
-
@new_cons_enabled = true
|
|
353
|
+
@threads_blocking_new_connections = 0
|
|
354
354
|
|
|
355
355
|
@available = ConnectionLeasingQueue.new self
|
|
356
356
|
end
|
|
@@ -415,7 +415,10 @@ module ActiveRecord
|
|
|
415
415
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
|
416
416
|
synchronize do
|
|
417
417
|
@connections.each do |conn|
|
|
418
|
-
|
|
418
|
+
if conn.in_use?
|
|
419
|
+
conn.steal!
|
|
420
|
+
checkin conn
|
|
421
|
+
end
|
|
419
422
|
conn.disconnect!
|
|
420
423
|
end
|
|
421
424
|
@connections = []
|
|
@@ -442,33 +445,19 @@ module ActiveRecord
|
|
|
442
445
|
# connections in the pool within a timeout interval (default duration is
|
|
443
446
|
# <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
|
|
444
447
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
|
445
|
-
num_new_conns_required = 0
|
|
446
|
-
|
|
447
448
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
|
448
449
|
synchronize do
|
|
449
450
|
@connections.each do |conn|
|
|
450
|
-
|
|
451
|
+
if conn.in_use?
|
|
452
|
+
conn.steal!
|
|
453
|
+
checkin conn
|
|
454
|
+
end
|
|
451
455
|
conn.disconnect! if conn.requires_reloading?
|
|
452
456
|
end
|
|
453
457
|
@connections.delete_if(&:requires_reloading?)
|
|
454
|
-
|
|
455
458
|
@available.clear
|
|
456
|
-
|
|
457
|
-
if @connections.size < @size
|
|
458
|
-
# because of the pruning done by this method, we might be running
|
|
459
|
-
# low on connections, while threads stuck in queue are helpless
|
|
460
|
-
# (not being able to establish new connections for themselves),
|
|
461
|
-
# see also more detailed explanation in +remove+
|
|
462
|
-
num_new_conns_required = num_waiting_in_queue - @connections.size
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
@connections.each do |conn|
|
|
466
|
-
@available.add conn
|
|
467
|
-
end
|
|
468
459
|
end
|
|
469
460
|
end
|
|
470
|
-
|
|
471
|
-
bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
|
|
472
461
|
end
|
|
473
462
|
|
|
474
463
|
# Clears the cache which maps classes and re-connects connections that
|
|
@@ -556,17 +545,17 @@ module ActiveRecord
|
|
|
556
545
|
stale_connections = synchronize do
|
|
557
546
|
@connections.select do |conn|
|
|
558
547
|
conn.in_use? && !conn.owner.alive?
|
|
548
|
+
end.each do |conn|
|
|
549
|
+
conn.steal!
|
|
559
550
|
end
|
|
560
551
|
end
|
|
561
552
|
|
|
562
553
|
stale_connections.each do |conn|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
remove conn
|
|
569
|
-
end
|
|
554
|
+
if conn.active?
|
|
555
|
+
conn.reset!
|
|
556
|
+
checkin conn
|
|
557
|
+
else
|
|
558
|
+
remove conn
|
|
570
559
|
end
|
|
571
560
|
end
|
|
572
561
|
end
|
|
@@ -675,13 +664,32 @@ module ActiveRecord
|
|
|
675
664
|
end
|
|
676
665
|
|
|
677
666
|
def with_new_connections_blocked
|
|
678
|
-
previous_value = nil
|
|
679
667
|
synchronize do
|
|
680
|
-
|
|
668
|
+
@threads_blocking_new_connections += 1
|
|
681
669
|
end
|
|
670
|
+
|
|
682
671
|
yield
|
|
683
672
|
ensure
|
|
684
|
-
|
|
673
|
+
num_new_conns_required = 0
|
|
674
|
+
|
|
675
|
+
synchronize do
|
|
676
|
+
@threads_blocking_new_connections -= 1
|
|
677
|
+
|
|
678
|
+
if @threads_blocking_new_connections.zero?
|
|
679
|
+
@available.clear
|
|
680
|
+
|
|
681
|
+
num_new_conns_required = num_waiting_in_queue
|
|
682
|
+
|
|
683
|
+
@connections.each do |conn|
|
|
684
|
+
next if conn.in_use?
|
|
685
|
+
|
|
686
|
+
@available.add conn
|
|
687
|
+
num_new_conns_required -= 1
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
|
|
685
693
|
end
|
|
686
694
|
|
|
687
695
|
# Acquire a connection by one of 1) immediately removing one
|
|
@@ -733,7 +741,7 @@ module ActiveRecord
|
|
|
733
741
|
# and increment @now_connecting, to prevent overstepping this pool's @size
|
|
734
742
|
# constraint
|
|
735
743
|
do_checkout = synchronize do
|
|
736
|
-
if @
|
|
744
|
+
if @threads_blocking_new_connections.zero? && (@connections.size + @now_connecting) < @size
|
|
737
745
|
@now_connecting += 1
|
|
738
746
|
end
|
|
739
747
|
end
|
|
@@ -244,7 +244,7 @@ module ActiveRecord
|
|
|
244
244
|
end
|
|
245
245
|
|
|
246
246
|
def reset_transaction #:nodoc:
|
|
247
|
-
@transaction_manager = TransactionManager.new(self)
|
|
247
|
+
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
|
248
248
|
end
|
|
249
249
|
|
|
250
250
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
|
@@ -4,6 +4,9 @@ module ActiveRecord
|
|
|
4
4
|
class << self
|
|
5
5
|
def included(base) #:nodoc:
|
|
6
6
|
dirties_query_cache base, :insert, :update, :delete, :rollback_to_savepoint, :rollback_db_transaction
|
|
7
|
+
|
|
8
|
+
base.set_callback :checkout, :after, :configure_query_cache!
|
|
9
|
+
base.set_callback :checkin, :after, :disable_query_cache!
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
def dirties_query_cache(base, *method_names)
|
|
@@ -18,6 +21,27 @@ module ActiveRecord
|
|
|
18
21
|
end
|
|
19
22
|
end
|
|
20
23
|
|
|
24
|
+
module ConnectionPoolConfiguration
|
|
25
|
+
def initialize(*)
|
|
26
|
+
super
|
|
27
|
+
@query_cache_enabled = Concurrent::Map.new { false }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def enable_query_cache!
|
|
31
|
+
@query_cache_enabled[connection_cache_key(Thread.current)] = true
|
|
32
|
+
connection.enable_query_cache! if active_connection?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def disable_query_cache!
|
|
36
|
+
@query_cache_enabled.delete connection_cache_key(Thread.current)
|
|
37
|
+
connection.disable_query_cache! if active_connection?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def query_cache_enabled
|
|
41
|
+
@query_cache_enabled[connection_cache_key(Thread.current)]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
21
45
|
attr_reader :query_cache, :query_cache_enabled
|
|
22
46
|
|
|
23
47
|
def initialize(*)
|
|
@@ -41,6 +65,7 @@ module ActiveRecord
|
|
|
41
65
|
|
|
42
66
|
def disable_query_cache!
|
|
43
67
|
@query_cache_enabled = false
|
|
68
|
+
clear_query_cache
|
|
44
69
|
end
|
|
45
70
|
|
|
46
71
|
# Disable the query cache within the block.
|
|
@@ -90,6 +115,10 @@ module ActiveRecord
|
|
|
90
115
|
def locked?(arel)
|
|
91
116
|
arel.respond_to?(:locked) && arel.locked
|
|
92
117
|
end
|
|
118
|
+
|
|
119
|
+
def configure_query_cache!
|
|
120
|
+
enable_query_cache! if pool.query_cache_enabled
|
|
121
|
+
end
|
|
93
122
|
end
|
|
94
123
|
end
|
|
95
124
|
end
|
|
@@ -112,19 +112,19 @@ module ActiveRecord
|
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def quoted_true
|
|
115
|
-
"'t'"
|
|
115
|
+
"'t'".freeze
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def unquoted_true
|
|
119
|
-
't'
|
|
119
|
+
't'.freeze
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
def quoted_false
|
|
123
|
-
"'f'"
|
|
123
|
+
"'f'".freeze
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def unquoted_false
|
|
127
|
-
'f'
|
|
127
|
+
'f'.freeze
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
# Quote date/time values for use in SQL input. Includes microseconds
|
|
@@ -51,11 +51,12 @@ module ActiveRecord
|
|
|
51
51
|
options[:primary_key] != default_primary_key
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
def defined_for?(
|
|
55
|
-
if
|
|
56
|
-
|
|
54
|
+
def defined_for?(to_table_ord = nil, to_table: nil, **options)
|
|
55
|
+
if to_table_ord
|
|
56
|
+
self.to_table == to_table_ord.to_s
|
|
57
57
|
else
|
|
58
|
-
to_table ==
|
|
58
|
+
(to_table.nil? || to_table.to_s == self.to_table) &&
|
|
59
|
+
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
|
|
@@ -211,7 +212,7 @@ module ActiveRecord
|
|
|
211
212
|
|
|
212
213
|
def initialize(name, temporary = false, options = nil, as = nil, comment: nil)
|
|
213
214
|
@columns_hash = {}
|
|
214
|
-
@indexes =
|
|
215
|
+
@indexes = []
|
|
215
216
|
@foreign_keys = []
|
|
216
217
|
@primary_keys = nil
|
|
217
218
|
@temporary = temporary
|
|
@@ -303,7 +304,7 @@ module ActiveRecord
|
|
|
303
304
|
# end
|
|
304
305
|
def column(name, type, options = {})
|
|
305
306
|
name = name.to_s
|
|
306
|
-
type = type.to_sym
|
|
307
|
+
type = type.to_sym if type
|
|
307
308
|
options = options.dup
|
|
308
309
|
|
|
309
310
|
if @columns_hash[name] && @columns_hash[name].primary_key?
|
|
@@ -327,7 +328,7 @@ module ActiveRecord
|
|
|
327
328
|
#
|
|
328
329
|
# index(:account_id, name: 'index_projects_on_account_id')
|
|
329
330
|
def index(column_name, options = {})
|
|
330
|
-
indexes[column_name
|
|
331
|
+
indexes << [column_name, options]
|
|
331
332
|
end
|
|
332
333
|
|
|
333
334
|
def foreign_key(table_name, options = {}) # :nodoc:
|
|
@@ -129,14 +129,9 @@ module ActiveRecord
|
|
|
129
129
|
|
|
130
130
|
# Returns just a table's primary key
|
|
131
131
|
def primary_key(table_name)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
#{table_name} has composite primary key. Composite primary key is ignored.
|
|
137
|
-
WARNING
|
|
138
|
-
|
|
139
|
-
pks.first if pks.one?
|
|
132
|
+
pk = primary_keys(table_name)
|
|
133
|
+
pk = pk.first unless pk.size > 1
|
|
134
|
+
pk
|
|
140
135
|
end
|
|
141
136
|
|
|
142
137
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
|
@@ -283,16 +278,16 @@ module ActiveRecord
|
|
|
283
278
|
result = execute schema_creation.accept td
|
|
284
279
|
|
|
285
280
|
unless supports_indexes_in_create?
|
|
286
|
-
td.indexes.
|
|
281
|
+
td.indexes.each do |column_name, index_options|
|
|
287
282
|
add_index(table_name, column_name, index_options)
|
|
288
283
|
end
|
|
289
284
|
end
|
|
290
285
|
|
|
291
286
|
if supports_comments? && !supports_comments_in_create?
|
|
292
|
-
change_table_comment(table_name, comment) if comment
|
|
287
|
+
change_table_comment(table_name, comment) if comment.present?
|
|
293
288
|
|
|
294
289
|
td.columns.each do |column|
|
|
295
|
-
change_column_comment(table_name, column.name, column.comment) if column.comment
|
|
290
|
+
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
|
296
291
|
end
|
|
297
292
|
end
|
|
298
293
|
|
|
@@ -790,7 +785,7 @@ module ActiveRecord
|
|
|
790
785
|
# [<tt>:type</tt>]
|
|
791
786
|
# The reference column type. Defaults to +:integer+.
|
|
792
787
|
# [<tt>:index</tt>]
|
|
793
|
-
# Add an appropriate index. Defaults to
|
|
788
|
+
# Add an appropriate index. Defaults to true.
|
|
794
789
|
# See #add_index for usage of this option.
|
|
795
790
|
# [<tt>:foreign_key</tt>]
|
|
796
791
|
# Add an appropriate foreign key constraint. Defaults to false.
|
|
@@ -847,14 +842,19 @@ module ActiveRecord
|
|
|
847
842
|
#
|
|
848
843
|
# remove_reference(:products, :user, index: true, foreign_key: true)
|
|
849
844
|
#
|
|
850
|
-
def remove_reference(table_name, ref_name,
|
|
851
|
-
if
|
|
845
|
+
def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
|
|
846
|
+
if foreign_key
|
|
852
847
|
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
|
853
|
-
|
|
848
|
+
if foreign_key.is_a?(Hash)
|
|
849
|
+
foreign_key_options = foreign_key
|
|
850
|
+
else
|
|
851
|
+
foreign_key_options = { to_table: reference_name }
|
|
852
|
+
end
|
|
853
|
+
remove_foreign_key(table_name, **foreign_key_options)
|
|
854
854
|
end
|
|
855
855
|
|
|
856
856
|
remove_column(table_name, "#{ref_name}_id")
|
|
857
|
-
remove_column(table_name, "#{ref_name}_type") if
|
|
857
|
+
remove_column(table_name, "#{ref_name}_type") if polymorphic
|
|
858
858
|
end
|
|
859
859
|
alias :remove_belongs_to :remove_reference
|
|
860
860
|
|
|
@@ -993,8 +993,8 @@ module ActiveRecord
|
|
|
993
993
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
|
994
994
|
|
|
995
995
|
if supports_multi_insert?
|
|
996
|
-
sql = "INSERT INTO #{sm_table} (version) VALUES
|
|
997
|
-
sql << versions.map {|v| "('#{v}')" }.join(
|
|
996
|
+
sql = "INSERT INTO #{sm_table} (version) VALUES\n"
|
|
997
|
+
sql << versions.map {|v| "('#{v}')" }.join(",\n")
|
|
998
998
|
sql << ";\n\n"
|
|
999
999
|
sql
|
|
1000
1000
|
else
|
|
@@ -1043,7 +1043,8 @@ module ActiveRecord
|
|
|
1043
1043
|
end
|
|
1044
1044
|
|
|
1045
1045
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
|
1046
|
-
|
|
1046
|
+
type = type.to_sym if type
|
|
1047
|
+
if native = native_database_types[type]
|
|
1047
1048
|
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
|
|
1048
1049
|
|
|
1049
1050
|
if type == :decimal # ignore limit, use precision and scale
|
|
@@ -1163,31 +1164,35 @@ module ActiveRecord
|
|
|
1163
1164
|
end
|
|
1164
1165
|
|
|
1165
1166
|
protected
|
|
1166
|
-
|
|
1167
|
-
|
|
1167
|
+
|
|
1168
|
+
def add_index_sort_order(quoted_columns, **options)
|
|
1169
|
+
if order = options[:order]
|
|
1168
1170
|
case order
|
|
1169
1171
|
when Hash
|
|
1170
|
-
|
|
1172
|
+
order = order.symbolize_keys
|
|
1173
|
+
quoted_columns.each { |name, column| column << " #{order[name].upcase}" if order[name].present? }
|
|
1171
1174
|
when String
|
|
1172
|
-
|
|
1175
|
+
quoted_columns.each { |name, column| column << " #{order.upcase}" if order.present? }
|
|
1173
1176
|
end
|
|
1174
1177
|
end
|
|
1175
1178
|
|
|
1176
|
-
|
|
1179
|
+
quoted_columns
|
|
1177
1180
|
end
|
|
1178
1181
|
|
|
1179
1182
|
# Overridden by the MySQL adapter for supporting index lengths
|
|
1180
|
-
def
|
|
1181
|
-
return [column_names] if column_names.is_a?(String)
|
|
1182
|
-
|
|
1183
|
-
option_strings = Hash[column_names.map {|name| [name, '']}]
|
|
1184
|
-
|
|
1185
|
-
# add index sort order if supported
|
|
1183
|
+
def add_options_for_index_columns(quoted_columns, **options)
|
|
1186
1184
|
if supports_index_sort_order?
|
|
1187
|
-
|
|
1185
|
+
quoted_columns = add_index_sort_order(quoted_columns, options)
|
|
1188
1186
|
end
|
|
1189
1187
|
|
|
1190
|
-
|
|
1188
|
+
quoted_columns
|
|
1189
|
+
end
|
|
1190
|
+
|
|
1191
|
+
def quoted_columns_for_index(column_names, **options)
|
|
1192
|
+
return [column_names] if column_names.is_a?(String)
|
|
1193
|
+
|
|
1194
|
+
quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }]
|
|
1195
|
+
add_options_for_index_columns(quoted_columns, options).values
|
|
1191
1196
|
end
|
|
1192
1197
|
|
|
1193
1198
|
def index_name_for_remove(table_name, options = {})
|
|
@@ -1210,7 +1215,7 @@ module ActiveRecord
|
|
|
1210
1215
|
checks << lambda { |i| i.columns.join('_and_') == column_names.join('_and_') }
|
|
1211
1216
|
end
|
|
1212
1217
|
|
|
1213
|
-
raise ArgumentError "No name or columns specified" if checks.none?
|
|
1218
|
+
raise ArgumentError, "No name or columns specified" if checks.none?
|
|
1214
1219
|
|
|
1215
1220
|
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
|
1216
1221
|
|