activerecord 6.0.0 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/associations/association.rb +9 -1
- data/lib/active_record/associations/join_dependency.rb +4 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +1 -1
- data/lib/active_record/autosave_association.rb +7 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +13 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +4 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +4 -0
- data/lib/active_record/connection_handling.rb +11 -4
- data/lib/active_record/core.rb +8 -4
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/middleware/database_selector/resolver.rb +8 -12
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/relation.rb +1 -0
- data/lib/active_record/relation/finder_methods.rb +10 -1
- data/lib/active_record/relation/query_methods.rb +15 -3
- data/lib/active_record/transactions.rb +1 -1
- data/lib/arel.rb +12 -5
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74e749ea0406c6090f479a06ed90ab6d7be8a341b3662329c623d212652ef0d3
|
4
|
+
data.tar.gz: 9daac4d5a5f794386f5580724c8a9f27c9a42c3db561d5a37ec314ac5715f0f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ae5468a2a52b707a9f111b1f416d6d3a63ebbfe1658f29f2d64062bbd0cd5408e7b620a4da8cabd8000ea484bbeecd2c70ecb36a94c9a2f91afac32a032ee73
|
7
|
+
data.tar.gz: 455c884ff4d115d562aa05df54beda3aea735b6b3fb0e29202280eca45fe9f4fad6d2b34a033fd6175048286fadd3ec90a975b02c54653f5a93fd9ac4a8f2d0b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,76 @@
|
|
1
|
+
## Rails 6.0.1 (November 5, 2019) ##
|
2
|
+
|
3
|
+
* Common Table Expressions are allowed on read-only connections.
|
4
|
+
|
5
|
+
*Chris Morris*
|
6
|
+
|
7
|
+
* New record instantiation respects `unscope`.
|
8
|
+
|
9
|
+
*Ryuta Kamizono*
|
10
|
+
|
11
|
+
* Fixed a case where `find_in_batches` could halt too early.
|
12
|
+
|
13
|
+
*Takayuki Nakata*
|
14
|
+
|
15
|
+
* Autosaved associations always perform validations when a custom validation
|
16
|
+
context is used.
|
17
|
+
|
18
|
+
*Tekin Suleyman*
|
19
|
+
|
20
|
+
* `sql.active_record` notifications now include the `:connection` in
|
21
|
+
their payloads.
|
22
|
+
|
23
|
+
*Eugene Kenny*
|
24
|
+
|
25
|
+
* A rollback encountered in an `after_commit` callback does not reset
|
26
|
+
previously-committed record state.
|
27
|
+
|
28
|
+
*Ryuta Kamizono*
|
29
|
+
|
30
|
+
* Fixed that join order was lost when eager-loading.
|
31
|
+
|
32
|
+
*Ryuta Kamizono*
|
33
|
+
|
34
|
+
* `DESCRIBE` queries are allowed on read-only connections.
|
35
|
+
|
36
|
+
*Dylan Thacker-Smith*
|
37
|
+
|
38
|
+
* Fixed that records that had been `inspect`ed could not be marshaled.
|
39
|
+
|
40
|
+
*Eugene Kenny*
|
41
|
+
|
42
|
+
* The connection pool reaper thread is respawned in forked processes. This
|
43
|
+
fixes that idle connections in forked processes wouldn't be reaped.
|
44
|
+
|
45
|
+
*John Hawthorn*
|
46
|
+
|
47
|
+
* The memoized result of `ActiveRecord::Relation#take` is properly cleared
|
48
|
+
when `ActiveRecord::Relation#reset` or `ActiveRecord::Relation#reload`
|
49
|
+
is called.
|
50
|
+
|
51
|
+
*Anmol Arora*
|
52
|
+
|
53
|
+
* Fixed the performance regression for `primary_keys` introduced MySQL 8.0.
|
54
|
+
|
55
|
+
*Hiroyuki Ishii*
|
56
|
+
|
57
|
+
* `insert`, `insert_all`, `upsert`, and `upsert_all` now clear the query cache.
|
58
|
+
|
59
|
+
*Eugene Kenny*
|
60
|
+
|
61
|
+
* Call `while_preventing_writes` directly from `connected_to`.
|
62
|
+
|
63
|
+
In some cases application authors want to use the database switching middleware and make explicit calls with `connected_to`. It's possible for an app to turn off writes and not turn them back on by the time we call `connected_to(role: :writing)`.
|
64
|
+
|
65
|
+
This change allows apps to fix this by assuming if a role is writing we want to allow writes, except in the case it's explicitly turned off.
|
66
|
+
|
67
|
+
*Eileen M. Uchitelle*
|
68
|
+
|
69
|
+
* Improve detection of ActiveRecord::StatementTimeout with mysql2 adapter in the edge case when the query is terminated during filesort.
|
70
|
+
|
71
|
+
*Kir Shatrov*
|
72
|
+
|
73
|
+
|
1
74
|
## Rails 6.0.0 (August 16, 2019) ##
|
2
75
|
|
3
76
|
* Preserve user supplied joins order as much as possible.
|
@@ -478,7 +551,7 @@
|
|
478
551
|
|
479
552
|
*Rafael Mendonça França*
|
480
553
|
|
481
|
-
* Deprecate `config.
|
554
|
+
* Deprecate `config.active_record.sqlite3.represent_boolean_as_integer`.
|
482
555
|
|
483
556
|
*Rafael Mendonça França*
|
484
557
|
|
@@ -15,17 +15,26 @@ module ActiveRecord
|
|
15
15
|
other == records
|
16
16
|
end
|
17
17
|
|
18
|
-
def build(
|
19
|
-
|
18
|
+
def build(attributes = nil, &block)
|
19
|
+
block = _deprecated_scope_block("new", &block)
|
20
|
+
@association.scoping(self) do
|
21
|
+
@association.build(attributes, &block)
|
22
|
+
end
|
20
23
|
end
|
21
24
|
alias new build
|
22
25
|
|
23
|
-
def create(
|
24
|
-
|
26
|
+
def create(attributes = nil, &block)
|
27
|
+
block = _deprecated_scope_block("create", &block)
|
28
|
+
@association.scoping(self) do
|
29
|
+
@association.create(attributes, &block)
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
|
-
def create!(
|
28
|
-
|
33
|
+
def create!(attributes = nil, &block)
|
34
|
+
block = _deprecated_scope_block("create!", &block)
|
35
|
+
@association.scoping(self) do
|
36
|
+
@association.create!(attributes, &block)
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
40
|
private
|
@@ -92,7 +92,7 @@ module ActiveRecord
|
|
92
92
|
through_reflection = reflection.through_reflection
|
93
93
|
source_reflection_names = reflection.source_reflection_names
|
94
94
|
source_associations = reflection.through_reflection.klass._reflections.keys
|
95
|
-
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or '
|
95
|
+
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}?")
|
96
96
|
else
|
97
97
|
super("Could not find the source association(s).")
|
98
98
|
end
|
@@ -43,6 +43,7 @@ module ActiveRecord
|
|
43
43
|
reflection.check_validity!
|
44
44
|
|
45
45
|
@owner, @reflection = owner, reflection
|
46
|
+
@_scope = nil
|
46
47
|
|
47
48
|
reset
|
48
49
|
reset_scope
|
@@ -95,7 +96,7 @@ module ActiveRecord
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def scope
|
98
|
-
target_scope.merge!(association_scope)
|
99
|
+
@_scope&.spawn || target_scope.merge!(association_scope)
|
99
100
|
end
|
100
101
|
|
101
102
|
def reset_scope
|
@@ -195,6 +196,13 @@ module ActiveRecord
|
|
195
196
|
_create_record(attributes, true, &block)
|
196
197
|
end
|
197
198
|
|
199
|
+
def scoping(relation, &block)
|
200
|
+
@_scope = relation
|
201
|
+
relation.scoping(&block)
|
202
|
+
ensure
|
203
|
+
@_scope = nil
|
204
|
+
end
|
205
|
+
|
198
206
|
private
|
199
207
|
def find_target
|
200
208
|
scope = self.scope
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
nodes = arel.constraints.first
|
38
38
|
|
39
39
|
others = nodes.children.extract! do |node|
|
40
|
-
Arel.fetch_attribute(node) { |attr| attr.relation.name
|
40
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
41
41
|
end
|
42
42
|
|
43
43
|
joins << table.create_join(table, table.create_on(nodes), join_type)
|
@@ -112,7 +112,7 @@ module ActiveRecord
|
|
112
112
|
association.flat_map { |parent, child|
|
113
113
|
grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
|
114
114
|
loaders = preloaders_for_reflection(reflection, reflection_records, scope)
|
115
|
-
recs = loaders.flat_map(&:preloaded_records)
|
115
|
+
recs = loaders.flat_map(&:preloaded_records).uniq
|
116
116
|
child_polymorphic_parent = reflection && reflection.options[:polymorphic]
|
117
117
|
loaders.concat Array.wrap(child).flat_map { |assoc|
|
118
118
|
preloaders_on assoc, recs, scope, child_polymorphic_parent
|
@@ -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 && record.changed_for_autosave?
|
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]
|
@@ -499,6 +499,10 @@ module ActiveRecord
|
|
499
499
|
end
|
500
500
|
end
|
501
501
|
|
502
|
+
def custom_validation_context?
|
503
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
504
|
+
end
|
505
|
+
|
502
506
|
def _ensure_no_duplicate_errors
|
503
507
|
errors.messages.each_key do |attribute|
|
504
508
|
errors[attribute].uniq!
|
@@ -317,14 +317,15 @@ module ActiveRecord
|
|
317
317
|
|
318
318
|
@mutex = Mutex.new
|
319
319
|
@pools = {}
|
320
|
+
@threads = {}
|
320
321
|
|
321
322
|
class << self
|
322
323
|
def register_pool(pool, frequency) # :nodoc:
|
323
324
|
@mutex.synchronize do
|
324
|
-
unless @
|
325
|
-
@
|
326
|
-
spawn_thread(frequency)
|
325
|
+
unless @threads[frequency]&.alive?
|
326
|
+
@threads[frequency] = spawn_thread(frequency)
|
327
327
|
end
|
328
|
+
@pools[frequency] ||= []
|
328
329
|
@pools[frequency] << WeakRef.new(pool)
|
329
330
|
end
|
330
331
|
end
|
@@ -333,7 +334,8 @@ module ActiveRecord
|
|
333
334
|
|
334
335
|
def spawn_thread(frequency)
|
335
336
|
Thread.new(frequency) do |t|
|
336
|
-
|
337
|
+
running = true
|
338
|
+
while running
|
337
339
|
sleep t
|
338
340
|
@mutex.synchronize do
|
339
341
|
@pools[frequency].select!(&:weakref_alive?)
|
@@ -342,6 +344,12 @@ module ActiveRecord
|
|
342
344
|
p.flush
|
343
345
|
rescue WeakRef::RefError
|
344
346
|
end
|
347
|
+
|
348
|
+
if @pools[frequency].empty?
|
349
|
+
@pools.delete(frequency)
|
350
|
+
@threads.delete(frequency)
|
351
|
+
running = false
|
352
|
+
end
|
345
353
|
end
|
346
354
|
end
|
347
355
|
end
|
@@ -642,6 +650,7 @@ module ActiveRecord
|
|
642
650
|
# or a thread dies unexpectedly.
|
643
651
|
def reap
|
644
652
|
stale_connections = synchronize do
|
653
|
+
return unless @connections
|
645
654
|
@connections.select do |conn|
|
646
655
|
conn.in_use? && !conn.owner.alive?
|
647
656
|
end.each do |conn|
|
@@ -666,6 +675,7 @@ module ActiveRecord
|
|
666
675
|
return if minimum_idle.nil?
|
667
676
|
|
668
677
|
idle_connections = synchronize do
|
678
|
+
return unless @connections
|
669
679
|
@connections.select do |conn|
|
670
680
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
671
681
|
end.each do |conn|
|
@@ -149,6 +149,10 @@ module ActiveRecord
|
|
149
149
|
exec_query(sql, name, binds)
|
150
150
|
end
|
151
151
|
|
152
|
+
def exec_insert_all(sql, name) # :nodoc:
|
153
|
+
exec_query(sql, name)
|
154
|
+
end
|
155
|
+
|
152
156
|
# Executes an INSERT query and returns the new record's ID
|
153
157
|
#
|
154
158
|
# +id_value+ will be returned unless the value is +nil+, in
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
class << self
|
9
9
|
def included(base) #:nodoc:
|
10
10
|
dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
|
-
:rollback_to_savepoint, :rollback_db_transaction
|
11
|
+
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
12
12
|
|
13
13
|
base.set_callback :checkout, :after, :configure_query_cache!
|
14
14
|
base.set_callback :checkin, :after, :disable_query_cache!
|
@@ -135,6 +135,7 @@ module ActiveRecord
|
|
135
135
|
type_casted_binds: -> { type_casted_binds(binds) },
|
136
136
|
name: name,
|
137
137
|
connection_id: object_id,
|
138
|
+
connection: self,
|
138
139
|
cached: true
|
139
140
|
}
|
140
141
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set"
|
3
4
|
require "active_record/connection_adapters/determine_if_preparable_visitor"
|
4
5
|
require "active_record/connection_adapters/schema_cache"
|
5
6
|
require "active_record/connection_adapters/sql_type_metadata"
|
@@ -11,7 +12,6 @@ require "arel/collectors/bind"
|
|
11
12
|
require "arel/collectors/composite"
|
12
13
|
require "arel/collectors/sql_string"
|
13
14
|
require "arel/collectors/substitute_binds"
|
14
|
-
require "concurrent/atomic/thread_local_var"
|
15
15
|
|
16
16
|
module ActiveRecord
|
17
17
|
module ConnectionAdapters # :nodoc:
|
@@ -130,10 +130,10 @@ module ActiveRecord
|
|
130
130
|
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
|
131
131
|
|
132
132
|
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
133
|
-
@
|
133
|
+
@prepared_statements = true
|
134
134
|
@visitor.extend(DetermineIfPreparableVisitor)
|
135
135
|
else
|
136
|
-
@
|
136
|
+
@prepared_statements = false
|
137
137
|
end
|
138
138
|
|
139
139
|
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
|
@@ -177,7 +177,11 @@ module ActiveRecord
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def prepared_statements
|
180
|
-
@
|
180
|
+
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
def prepared_statements_disabled_cache # :nodoc:
|
184
|
+
Thread.current[:ar_prepared_statements_disabled_cache] ||= Set.new
|
181
185
|
end
|
182
186
|
|
183
187
|
class Version
|
@@ -264,7 +268,10 @@ module ActiveRecord
|
|
264
268
|
end
|
265
269
|
|
266
270
|
def unprepared_statement
|
267
|
-
|
271
|
+
cache = prepared_statements_disabled_cache.add(object_id) if @prepared_statements
|
272
|
+
yield
|
273
|
+
ensure
|
274
|
+
cache&.delete(object_id)
|
268
275
|
end
|
269
276
|
|
270
277
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
@@ -409,6 +416,10 @@ module ActiveRecord
|
|
409
416
|
false
|
410
417
|
end
|
411
418
|
|
419
|
+
def supports_common_table_expressions?
|
420
|
+
false
|
421
|
+
end
|
422
|
+
|
412
423
|
def supports_lazy_transactions?
|
413
424
|
false
|
414
425
|
end
|
@@ -110,6 +110,14 @@ module ActiveRecord
|
|
110
110
|
!mariadb? && database_version >= "5.7.7"
|
111
111
|
end
|
112
112
|
|
113
|
+
def supports_common_table_expressions?
|
114
|
+
if mariadb?
|
115
|
+
database_version >= "10.2.1"
|
116
|
+
else
|
117
|
+
database_version >= "8.0.1"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
113
121
|
def supports_advisory_locks?
|
114
122
|
true
|
115
123
|
end
|
@@ -440,11 +448,11 @@ module ActiveRecord
|
|
440
448
|
|
441
449
|
query_values(<<~SQL, "SCHEMA")
|
442
450
|
SELECT column_name
|
443
|
-
FROM information_schema.
|
444
|
-
WHERE
|
451
|
+
FROM information_schema.statistics
|
452
|
+
WHERE index_name = 'PRIMARY'
|
445
453
|
AND table_schema = #{scope[:schema]}
|
446
454
|
AND table_name = #{scope[:name]}
|
447
|
-
ORDER BY
|
455
|
+
ORDER BY seq_in_index
|
448
456
|
SQL
|
449
457
|
end
|
450
458
|
|
@@ -581,6 +589,7 @@ module ActiveRecord
|
|
581
589
|
end
|
582
590
|
|
583
591
|
# See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
|
592
|
+
ER_FILSORT_ABORT = 1028
|
584
593
|
ER_DUP_ENTRY = 1062
|
585
594
|
ER_NOT_NULL_VIOLATION = 1048
|
586
595
|
ER_NO_REFERENCED_ROW = 1216
|
@@ -622,7 +631,7 @@ module ActiveRecord
|
|
622
631
|
Deadlocked.new(message, sql: sql, binds: binds)
|
623
632
|
when ER_LOCK_WAIT_TIMEOUT
|
624
633
|
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
625
|
-
when ER_QUERY_TIMEOUT
|
634
|
+
when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
|
626
635
|
StatementTimeout.new(message, sql: sql, binds: binds)
|
627
636
|
when ER_QUERY_INTERRUPTED
|
628
637
|
QueryCanceled.new(message, sql: sql, binds: binds)
|
@@ -186,7 +186,7 @@ module ActiveRecord
|
|
186
186
|
adapter_method = "#{spec[:adapter]}_connection"
|
187
187
|
|
188
188
|
unless ActiveRecord::Base.respond_to?(adapter_method)
|
189
|
-
raise AdapterNotFound, "database configuration specifies nonexistent #{spec
|
189
|
+
raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
|
190
190
|
end
|
191
191
|
|
192
192
|
ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method)
|
@@ -19,7 +19,9 @@ module ActiveRecord
|
|
19
19
|
execute(sql, name).to_a
|
20
20
|
end
|
21
21
|
|
22
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
22
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
23
|
+
:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :describe, :desc, :with
|
24
|
+
) # :nodoc:
|
23
25
|
private_constant :READ_QUERY
|
24
26
|
|
25
27
|
def write_query?(sql) # :nodoc:
|
@@ -67,7 +67,9 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
70
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
71
|
+
:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :with
|
72
|
+
) # :nodoc:
|
71
73
|
private_constant :READ_QUERY
|
72
74
|
|
73
75
|
def write_query?(sql) # :nodoc:
|
@@ -4,7 +4,9 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLite3
|
6
6
|
module DatabaseStatements
|
7
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
7
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
8
|
+
:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback, :with
|
9
|
+
) # :nodoc:
|
8
10
|
private_constant :READ_QUERY
|
9
11
|
|
10
12
|
def write_query?(sql) # :nodoc:
|
@@ -113,8 +113,9 @@ module ActiveRecord
|
|
113
113
|
# Dog.run_a_long_query
|
114
114
|
# end
|
115
115
|
#
|
116
|
-
# When using the database key a new connection will be established every time.
|
117
|
-
|
116
|
+
# When using the database key a new connection will be established every time. It is not
|
117
|
+
# recommended to use this outside of one-off scripts.
|
118
|
+
def connected_to(database: nil, role: nil, prevent_writes: false, &blk)
|
118
119
|
if database && role
|
119
120
|
raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
|
120
121
|
elsif database
|
@@ -130,7 +131,13 @@ module ActiveRecord
|
|
130
131
|
|
131
132
|
with_handler(role, &blk)
|
132
133
|
elsif role
|
133
|
-
|
134
|
+
if role == writing_role
|
135
|
+
with_handler(role.to_sym) do
|
136
|
+
connection_handler.while_preventing_writes(prevent_writes, &blk)
|
137
|
+
end
|
138
|
+
else
|
139
|
+
with_handler(role.to_sym, &blk)
|
140
|
+
end
|
134
141
|
else
|
135
142
|
raise ArgumentError, "must provide a `database` or a `role`."
|
136
143
|
end
|
@@ -204,7 +211,7 @@ module ActiveRecord
|
|
204
211
|
# Return the specification name from the current class or its parent.
|
205
212
|
def connection_specification_name
|
206
213
|
if !defined?(@connection_specification_name) || @connection_specification_name.nil?
|
207
|
-
return
|
214
|
+
return self == Base ? "primary" : superclass.connection_specification_name
|
208
215
|
end
|
209
216
|
@connection_specification_name
|
210
217
|
end
|
data/lib/active_record/core.rb
CHANGED
@@ -586,12 +586,16 @@ module ActiveRecord
|
|
586
586
|
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
587
587
|
end
|
588
588
|
|
589
|
+
class InspectionMask < DelegateClass(::String)
|
590
|
+
def pretty_print(pp)
|
591
|
+
pp.text __getobj__
|
592
|
+
end
|
593
|
+
end
|
594
|
+
private_constant :InspectionMask
|
595
|
+
|
589
596
|
def inspection_filter
|
590
597
|
@inspection_filter ||= begin
|
591
|
-
mask =
|
592
|
-
def mask.pretty_print(pp)
|
593
|
-
pp.text __getobj__
|
594
|
-
end
|
598
|
+
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
595
599
|
ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
|
596
600
|
end
|
597
601
|
end
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
message = +"#{model} "
|
25
25
|
message << "Bulk " if inserts.many?
|
26
26
|
message << (on_duplicate == :update ? "Upsert" : "Insert")
|
27
|
-
connection.
|
27
|
+
connection.exec_insert_all to_sql, message
|
28
28
|
end
|
29
29
|
|
30
30
|
def updatable_columns
|
@@ -46,11 +46,9 @@ module ActiveRecord
|
|
46
46
|
private
|
47
47
|
|
48
48
|
def read_from_primary(&blk)
|
49
|
-
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
50
|
-
|
51
|
-
|
52
|
-
yield
|
53
|
-
end
|
49
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
|
50
|
+
instrumenter.instrument("database_selector.active_record.read_from_primary") do
|
51
|
+
yield
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
@@ -64,13 +62,11 @@ module ActiveRecord
|
|
64
62
|
end
|
65
63
|
|
66
64
|
def write_to_primary(&blk)
|
67
|
-
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
context.update_last_write_timestamp
|
73
|
-
end
|
65
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do
|
66
|
+
instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
|
67
|
+
yield
|
68
|
+
ensure
|
69
|
+
context.update_last_write_timestamp
|
74
70
|
end
|
75
71
|
end
|
76
72
|
end
|
@@ -376,7 +376,16 @@ module ActiveRecord
|
|
376
376
|
)
|
377
377
|
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
378
378
|
|
379
|
-
if eager_loading && !
|
379
|
+
if eager_loading && !(
|
380
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
381
|
+
using_limitable_reflections?(
|
382
|
+
construct_join_dependency(
|
383
|
+
select_association_list(joins_values).concat(
|
384
|
+
select_association_list(left_outer_joins_values)
|
385
|
+
), nil
|
386
|
+
).reflections
|
387
|
+
)
|
388
|
+
)
|
380
389
|
if has_limit_or_offset?
|
381
390
|
limited_ids = limited_ids_for(relation)
|
382
391
|
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
@@ -1083,15 +1083,23 @@ module ActiveRecord
|
|
1083
1083
|
end
|
1084
1084
|
end
|
1085
1085
|
|
1086
|
-
def
|
1086
|
+
def select_association_list(associations)
|
1087
|
+
result = []
|
1087
1088
|
associations.each do |association|
|
1088
1089
|
case association
|
1089
1090
|
when Hash, Symbol, Array
|
1090
|
-
|
1091
|
+
result << association
|
1091
1092
|
else
|
1092
|
-
|
1093
|
+
yield if block_given?
|
1093
1094
|
end
|
1094
1095
|
end
|
1096
|
+
result
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def valid_association_list(associations)
|
1100
|
+
select_association_list(associations) do
|
1101
|
+
raise ArgumentError, "only Hash, Symbol and Array are allowed"
|
1102
|
+
end
|
1095
1103
|
end
|
1096
1104
|
|
1097
1105
|
def build_left_outer_joins(manager, outer_joins, aliases)
|
@@ -1108,6 +1116,10 @@ module ActiveRecord
|
|
1108
1116
|
buckets[:stashed_join] << construct_join_dependency(left_joins, Arel::Nodes::OuterJoin)
|
1109
1117
|
end
|
1110
1118
|
|
1119
|
+
if joins.last.is_a?(ActiveRecord::Associations::JoinDependency)
|
1120
|
+
buckets[:stashed_join] << joins.pop if joins.last.base_klass == klass
|
1121
|
+
end
|
1122
|
+
|
1111
1123
|
joins.map! do |join|
|
1112
1124
|
if join.is_a?(String)
|
1113
1125
|
table.create_string_join(Arel.sql(join.strip)) unless join.blank?
|
@@ -333,6 +333,7 @@ module ActiveRecord
|
|
333
333
|
# Ensure that it is not called if the object was never persisted (failed create),
|
334
334
|
# but call it after the commit of a destroyed object.
|
335
335
|
def committed!(should_run_callbacks: true) #:nodoc:
|
336
|
+
force_clear_transaction_record_state
|
336
337
|
if should_run_callbacks
|
337
338
|
@_committed_already_called = true
|
338
339
|
_run_commit_without_transaction_enrollment_callbacks
|
@@ -340,7 +341,6 @@ module ActiveRecord
|
|
340
341
|
end
|
341
342
|
ensure
|
342
343
|
@_committed_already_called = false
|
343
|
-
force_clear_transaction_record_state
|
344
344
|
end
|
345
345
|
|
346
346
|
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
|
data/lib/arel.rb
CHANGED
@@ -24,22 +24,29 @@ require "arel/update_manager"
|
|
24
24
|
require "arel/delete_manager"
|
25
25
|
require "arel/nodes"
|
26
26
|
|
27
|
-
module Arel
|
27
|
+
module Arel
|
28
28
|
VERSION = "10.0.0"
|
29
29
|
|
30
|
+
# Wrap a known-safe SQL string for passing to query methods, e.g.
|
31
|
+
#
|
32
|
+
# Post.order(Arel.sql("length(title)")).last
|
33
|
+
#
|
34
|
+
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
35
|
+
# This method should not be used with unsafe values such as request
|
36
|
+
# parameters or model attributes.
|
30
37
|
def self.sql(raw_sql)
|
31
38
|
Arel::Nodes::SqlLiteral.new raw_sql
|
32
39
|
end
|
33
40
|
|
34
|
-
def self.star
|
41
|
+
def self.star # :nodoc:
|
35
42
|
sql "*"
|
36
43
|
end
|
37
44
|
|
38
|
-
def self.arel_node?(value)
|
45
|
+
def self.arel_node?(value) # :nodoc:
|
39
46
|
value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
|
40
47
|
end
|
41
48
|
|
42
|
-
def self.fetch_attribute(value)
|
49
|
+
def self.fetch_attribute(value) # :nodoc:
|
43
50
|
case value
|
44
51
|
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
45
52
|
yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
|
@@ -47,5 +54,5 @@ module Arel # :nodoc: all
|
|
47
54
|
end
|
48
55
|
|
49
56
|
## Convenience Alias
|
50
|
-
Node = Arel::Nodes::Node
|
57
|
+
Node = Arel::Nodes::Node # :nodoc:
|
51
58
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.
|
4
|
+
version: 6.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.
|
19
|
+
version: 6.0.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.0.
|
26
|
+
version: 6.0.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 6.0.
|
33
|
+
version: 6.0.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 6.0.
|
40
|
+
version: 6.0.1
|
41
41
|
description: Databases on Rails. Build a persistent domain model by mapping database
|
42
42
|
tables to Ruby classes. Strong conventions for associations, validations, aggregations,
|
43
43
|
migrations, and testing come baked-in.
|
@@ -389,8 +389,11 @@ homepage: https://rubyonrails.org
|
|
389
389
|
licenses:
|
390
390
|
- MIT
|
391
391
|
metadata:
|
392
|
-
|
393
|
-
changelog_uri: https://github.com/rails/rails/blob/v6.0.
|
392
|
+
bug_tracker_uri: https://github.com/rails/rails/issues
|
393
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.0.1/activerecord/CHANGELOG.md
|
394
|
+
documentation_uri: https://api.rubyonrails.org/v6.0.1/
|
395
|
+
mailing_list_uri: https://groups.google.com/forum/#!forum/rubyonrails-talk
|
396
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.0.1/activerecord
|
394
397
|
post_install_message:
|
395
398
|
rdoc_options:
|
396
399
|
- "--main"
|
@@ -408,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
408
411
|
- !ruby/object:Gem::Version
|
409
412
|
version: '0'
|
410
413
|
requirements: []
|
411
|
-
rubygems_version: 3.0.
|
414
|
+
rubygems_version: 3.0.3
|
412
415
|
signing_key:
|
413
416
|
specification_version: 4
|
414
417
|
summary: Object-relational mapper framework (part of Rails).
|