activerecord 5.2.2.1 → 6.0.2
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 +734 -508
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +16 -28
- data/lib/active_record/associations/collection_proxy.rb +19 -48
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +3 -10
- data/lib/active_record/associations/has_many_through_association.rb +20 -25
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +22 -8
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +137 -26
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +114 -130
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +7 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -77
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +104 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +30 -16
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +91 -64
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +231 -25
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -22
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +67 -57
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +28 -28
- data/lib/active_record/relation/merger.rb +17 -23
- data/lib/active_record/relation/predicate_builder.rb +18 -15
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +17 -10
- data/lib/active_record/relation/query_methods.rb +247 -73
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +111 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -3,6 +3,7 @@
|
|
3
3
|
require "thread"
|
4
4
|
require "concurrent/map"
|
5
5
|
require "monitor"
|
6
|
+
require "weakref"
|
6
7
|
|
7
8
|
module ActiveRecord
|
8
9
|
# Raised when a connection could not be obtained within the connection
|
@@ -19,6 +20,26 @@ module ActiveRecord
|
|
19
20
|
end
|
20
21
|
|
21
22
|
module ConnectionAdapters
|
23
|
+
module AbstractPool # :nodoc:
|
24
|
+
def get_schema_cache(connection)
|
25
|
+
@schema_cache ||= SchemaCache.new(connection)
|
26
|
+
@schema_cache.connection = connection
|
27
|
+
@schema_cache
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_schema_cache(cache)
|
31
|
+
@schema_cache = cache
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class NullPool # :nodoc:
|
36
|
+
include ConnectionAdapters::AbstractPool
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
@schema_cache = nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
22
43
|
# Connection pool base class for managing Active Record database
|
23
44
|
# connections.
|
24
45
|
#
|
@@ -185,7 +206,7 @@ module ActiveRecord
|
|
185
206
|
def wait_poll(timeout)
|
186
207
|
@num_waiting += 1
|
187
208
|
|
188
|
-
t0 =
|
209
|
+
t0 = Concurrent.monotonic_time
|
189
210
|
elapsed = 0
|
190
211
|
loop do
|
191
212
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -194,7 +215,7 @@ module ActiveRecord
|
|
194
215
|
|
195
216
|
return remove if any?
|
196
217
|
|
197
|
-
elapsed =
|
218
|
+
elapsed = Concurrent.monotonic_time - t0
|
198
219
|
if elapsed >= timeout
|
199
220
|
msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
|
200
221
|
[timeout, elapsed]
|
@@ -294,23 +315,59 @@ module ActiveRecord
|
|
294
315
|
@frequency = frequency
|
295
316
|
end
|
296
317
|
|
318
|
+
@mutex = Mutex.new
|
319
|
+
@pools = {}
|
320
|
+
@threads = {}
|
321
|
+
|
322
|
+
class << self
|
323
|
+
def register_pool(pool, frequency) # :nodoc:
|
324
|
+
@mutex.synchronize do
|
325
|
+
unless @threads[frequency]&.alive?
|
326
|
+
@threads[frequency] = spawn_thread(frequency)
|
327
|
+
end
|
328
|
+
@pools[frequency] ||= []
|
329
|
+
@pools[frequency] << WeakRef.new(pool)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
private
|
334
|
+
|
335
|
+
def spawn_thread(frequency)
|
336
|
+
Thread.new(frequency) do |t|
|
337
|
+
running = true
|
338
|
+
while running
|
339
|
+
sleep t
|
340
|
+
@mutex.synchronize do
|
341
|
+
@pools[frequency].select!(&:weakref_alive?)
|
342
|
+
@pools[frequency].each do |p|
|
343
|
+
p.reap
|
344
|
+
p.flush
|
345
|
+
rescue WeakRef::RefError
|
346
|
+
end
|
347
|
+
|
348
|
+
if @pools[frequency].empty?
|
349
|
+
@pools.delete(frequency)
|
350
|
+
@threads.delete(frequency)
|
351
|
+
running = false
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
297
359
|
def run
|
298
360
|
return unless frequency && frequency > 0
|
299
|
-
|
300
|
-
loop do
|
301
|
-
sleep t
|
302
|
-
p.reap
|
303
|
-
p.flush
|
304
|
-
end
|
305
|
-
}
|
361
|
+
self.class.register_pool(pool, frequency)
|
306
362
|
end
|
307
363
|
end
|
308
364
|
|
309
365
|
include MonitorMixin
|
310
366
|
include QueryCache::ConnectionPoolConfiguration
|
367
|
+
include ConnectionAdapters::AbstractPool
|
311
368
|
|
312
369
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
313
|
-
attr_reader :spec, :
|
370
|
+
attr_reader :spec, :size, :reaper
|
314
371
|
|
315
372
|
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
|
316
373
|
# object which describes database connection information (e.g. adapter,
|
@@ -379,7 +436,7 @@ module ActiveRecord
|
|
379
436
|
# #connection can be called any number of times; the connection is
|
380
437
|
# held in a cache keyed by a thread.
|
381
438
|
def connection
|
382
|
-
@thread_cached_conns[connection_cache_key(
|
439
|
+
@thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
|
383
440
|
end
|
384
441
|
|
385
442
|
# Returns true if there is an open connection being used for the current thread.
|
@@ -388,7 +445,7 @@ module ActiveRecord
|
|
388
445
|
# #connection or #with_connection methods. Connections obtained through
|
389
446
|
# #checkout will not be detected by #active_connection?
|
390
447
|
def active_connection?
|
391
|
-
@thread_cached_conns[connection_cache_key(
|
448
|
+
@thread_cached_conns[connection_cache_key(current_thread)]
|
392
449
|
end
|
393
450
|
|
394
451
|
# Signal that the thread is finished with the current connection.
|
@@ -423,6 +480,21 @@ module ActiveRecord
|
|
423
480
|
synchronize { @connections.any? }
|
424
481
|
end
|
425
482
|
|
483
|
+
# Returns an array containing the connections currently in the pool.
|
484
|
+
# Access to the array does not require synchronization on the pool because
|
485
|
+
# the array is newly created and not retained by the pool.
|
486
|
+
#
|
487
|
+
# However; this method bypasses the ConnectionPool's thread-safe connection
|
488
|
+
# access pattern. A returned connection may be owned by another thread,
|
489
|
+
# unowned, or by happen-stance owned by the calling thread.
|
490
|
+
#
|
491
|
+
# Calling methods on a connection without ownership is subject to the
|
492
|
+
# thread-safety guarantees of the underlying method. Many of the methods
|
493
|
+
# on connection adapter classes are inherently multi-thread unsafe.
|
494
|
+
def connections
|
495
|
+
synchronize { @connections.dup }
|
496
|
+
end
|
497
|
+
|
426
498
|
# Disconnects all connections in the pool, and clears the pool.
|
427
499
|
#
|
428
500
|
# Raises:
|
@@ -578,6 +650,7 @@ module ActiveRecord
|
|
578
650
|
# or a thread dies unexpectedly.
|
579
651
|
def reap
|
580
652
|
stale_connections = synchronize do
|
653
|
+
return unless @connections
|
581
654
|
@connections.select do |conn|
|
582
655
|
conn.in_use? && !conn.owner.alive?
|
583
656
|
end.each do |conn|
|
@@ -602,6 +675,7 @@ module ActiveRecord
|
|
602
675
|
return if minimum_idle.nil?
|
603
676
|
|
604
677
|
idle_connections = synchronize do
|
678
|
+
return unless @connections
|
605
679
|
@connections.select do |conn|
|
606
680
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
607
681
|
end.each do |conn|
|
@@ -668,6 +742,10 @@ module ActiveRecord
|
|
668
742
|
thread
|
669
743
|
end
|
670
744
|
|
745
|
+
def current_thread
|
746
|
+
@lock_thread || Thread.current
|
747
|
+
end
|
748
|
+
|
671
749
|
# Take control of all existing connections so a "group" action such as
|
672
750
|
# reload/disconnect can be performed safely. It is no longer enough to
|
673
751
|
# wrap it in +synchronize+ because some pool's actions are allowed
|
@@ -686,13 +764,13 @@ module ActiveRecord
|
|
686
764
|
end
|
687
765
|
|
688
766
|
newly_checked_out = []
|
689
|
-
timeout_time =
|
767
|
+
timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
|
690
768
|
|
691
769
|
@available.with_a_bias_for(Thread.current) do
|
692
770
|
loop do
|
693
771
|
synchronize do
|
694
772
|
return if collected_conns.size == @connections.size && @now_connecting == 0
|
695
|
-
remaining_timeout = timeout_time -
|
773
|
+
remaining_timeout = timeout_time - Concurrent.monotonic_time
|
696
774
|
remaining_timeout = 0 if remaining_timeout < 0
|
697
775
|
conn = checkout_for_exclusive_access(remaining_timeout)
|
698
776
|
collected_conns << conn
|
@@ -731,7 +809,7 @@ module ActiveRecord
|
|
731
809
|
# this block can't be easily moved into attempt_to_checkout_all_existing_connections's
|
732
810
|
# rescue block, because doing so would put it outside of synchronize section, without
|
733
811
|
# being in a critical section thread_report might become inaccurate
|
734
|
-
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
812
|
+
msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
735
813
|
|
736
814
|
thread_report = []
|
737
815
|
@connections.each do |conn|
|
@@ -809,7 +887,7 @@ module ActiveRecord
|
|
809
887
|
|
810
888
|
def new_connection
|
811
889
|
Base.send(spec.adapter_method, spec.config).tap do |conn|
|
812
|
-
conn.
|
890
|
+
conn.check_version
|
813
891
|
end
|
814
892
|
end
|
815
893
|
|
@@ -915,6 +993,16 @@ module ActiveRecord
|
|
915
993
|
# about the model. The model needs to pass a specification name to the handler,
|
916
994
|
# in order to look up the correct connection pool.
|
917
995
|
class ConnectionHandler
|
996
|
+
def self.create_owner_to_pool # :nodoc:
|
997
|
+
Concurrent::Map.new(initial_capacity: 2) do |h, k|
|
998
|
+
# Discard the parent's connection pools immediately; we have no need
|
999
|
+
# of them
|
1000
|
+
discard_unowned_pools(h)
|
1001
|
+
|
1002
|
+
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
918
1006
|
def self.unowned_pool_finalizer(pid_map) # :nodoc:
|
919
1007
|
lambda do |_|
|
920
1008
|
discard_unowned_pools(pid_map)
|
@@ -929,19 +1017,33 @@ module ActiveRecord
|
|
929
1017
|
|
930
1018
|
def initialize
|
931
1019
|
# These caches are keyed by spec.name (ConnectionSpecification#name).
|
932
|
-
@owner_to_pool =
|
933
|
-
# Discard the parent's connection pools immediately; we have no need
|
934
|
-
# of them
|
935
|
-
ConnectionHandler.discard_unowned_pools(h)
|
936
|
-
|
937
|
-
h[k] = Concurrent::Map.new(initial_capacity: 2)
|
938
|
-
end
|
1020
|
+
@owner_to_pool = ConnectionHandler.create_owner_to_pool
|
939
1021
|
|
940
1022
|
# Backup finalizer: if the forked child never needed a pool, the above
|
941
1023
|
# early discard has not occurred
|
942
1024
|
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
943
1025
|
end
|
944
1026
|
|
1027
|
+
def prevent_writes # :nodoc:
|
1028
|
+
Thread.current[:prevent_writes]
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
def prevent_writes=(prevent_writes) # :nodoc:
|
1032
|
+
Thread.current[:prevent_writes] = prevent_writes
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
# Prevent writing to the database regardless of role.
|
1036
|
+
#
|
1037
|
+
# In some cases you may want to prevent writes to the database
|
1038
|
+
# even if you are on a database that can write. `while_preventing_writes`
|
1039
|
+
# will prevent writes to the database for the duration of the block.
|
1040
|
+
def while_preventing_writes(enabled = true)
|
1041
|
+
original, self.prevent_writes = self.prevent_writes, enabled
|
1042
|
+
yield
|
1043
|
+
ensure
|
1044
|
+
self.prevent_writes = original
|
1045
|
+
end
|
1046
|
+
|
945
1047
|
def connection_pool_list
|
946
1048
|
owner_to_pool.values.compact
|
947
1049
|
end
|
@@ -1006,15 +1108,24 @@ module ActiveRecord
|
|
1006
1108
|
# for (not necessarily the current class).
|
1007
1109
|
def retrieve_connection(spec_name) #:nodoc:
|
1008
1110
|
pool = retrieve_connection_pool(spec_name)
|
1009
|
-
|
1111
|
+
|
1112
|
+
unless pool
|
1113
|
+
# multiple database application
|
1114
|
+
if ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
|
1115
|
+
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
|
1116
|
+
else
|
1117
|
+
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found."
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1010
1121
|
pool.connection
|
1011
1122
|
end
|
1012
1123
|
|
1013
1124
|
# Returns true if a connection that's accessible to this class has
|
1014
1125
|
# already been opened.
|
1015
1126
|
def connected?(spec_name)
|
1016
|
-
|
1017
|
-
|
1127
|
+
pool = retrieve_connection_pool(spec_name)
|
1128
|
+
pool && pool.connected?
|
1018
1129
|
end
|
1019
1130
|
|
1020
1131
|
# Remove the connection for this class. This will close the active
|
@@ -1,22 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/deprecation"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters # :nodoc:
|
5
7
|
module DatabaseLimits
|
8
|
+
def max_identifier_length # :nodoc:
|
9
|
+
64
|
10
|
+
end
|
11
|
+
|
6
12
|
# Returns the maximum length of a table alias.
|
7
13
|
def table_alias_length
|
8
|
-
|
14
|
+
max_identifier_length
|
9
15
|
end
|
10
16
|
|
11
17
|
# Returns the maximum length of a column name.
|
12
18
|
def column_name_length
|
13
|
-
|
19
|
+
max_identifier_length
|
14
20
|
end
|
21
|
+
deprecate :column_name_length
|
15
22
|
|
16
23
|
# Returns the maximum length of a table name.
|
17
24
|
def table_name_length
|
18
|
-
|
25
|
+
max_identifier_length
|
19
26
|
end
|
27
|
+
deprecate :table_name_length
|
20
28
|
|
21
29
|
# Returns the maximum allowed length for an index name. This
|
22
30
|
# limit is enforced by \Rails and is less than or equal to
|
@@ -29,23 +37,26 @@ module ActiveRecord
|
|
29
37
|
|
30
38
|
# Returns the maximum length of an index name.
|
31
39
|
def index_name_length
|
32
|
-
|
40
|
+
max_identifier_length
|
33
41
|
end
|
34
42
|
|
35
43
|
# Returns the maximum number of columns per table.
|
36
44
|
def columns_per_table
|
37
45
|
1024
|
38
46
|
end
|
47
|
+
deprecate :columns_per_table
|
39
48
|
|
40
49
|
# Returns the maximum number of indexes per table.
|
41
50
|
def indexes_per_table
|
42
51
|
16
|
43
52
|
end
|
53
|
+
deprecate :indexes_per_table
|
44
54
|
|
45
55
|
# Returns the maximum number of columns in a multicolumn index.
|
46
56
|
def columns_per_multicolumn_index
|
47
57
|
16
|
48
58
|
end
|
59
|
+
deprecate :columns_per_multicolumn_index
|
49
60
|
|
50
61
|
# Returns the maximum number of elements in an IN (x,y,z) clause.
|
51
62
|
# +nil+ means no limit.
|
@@ -57,11 +68,13 @@ module ActiveRecord
|
|
57
68
|
def sql_query_length
|
58
69
|
1048575
|
59
70
|
end
|
71
|
+
deprecate :sql_query_length
|
60
72
|
|
61
73
|
# Returns maximum number of joins in a single query.
|
62
74
|
def joins_per_query
|
63
75
|
256
|
64
76
|
end
|
77
|
+
deprecate :joins_per_query
|
65
78
|
|
66
79
|
private
|
67
80
|
def bind_params_length
|
@@ -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.compile(arel_or_sql_string.ast, collector)
|
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.compile(arel_or_sql_string.ast, collector)
|
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
|
@@ -32,11 +45,11 @@ module ActiveRecord
|
|
32
45
|
# can be used to query the database repeatedly.
|
33
46
|
def cacheable_query(klass, arel) # :nodoc:
|
34
47
|
if prepared_statements
|
35
|
-
sql, binds = visitor.
|
48
|
+
sql, binds = visitor.compile(arel.ast, collector)
|
36
49
|
query = klass.query(sql)
|
37
50
|
else
|
38
|
-
collector =
|
39
|
-
parts, binds = visitor.
|
51
|
+
collector = klass.partial_query_collector
|
52
|
+
parts, binds = visitor.compile(arel.ast, collector)
|
40
53
|
query = klass.partial_query(parts)
|
41
54
|
end
|
42
55
|
[query, binds]
|
@@ -47,13 +60,8 @@ module ActiveRecord
|
|
47
60
|
arel = arel_from_relation(arel)
|
48
61
|
sql, binds = to_sql_and_binds(arel, binds)
|
49
62
|
|
50
|
-
if
|
51
|
-
preparable = false
|
52
|
-
elsif binds.length > bind_params_length
|
53
|
-
sql, binds = unprepared_statement { to_sql_and_binds(arel) }
|
54
|
-
preparable = false
|
55
|
-
else
|
56
|
-
preparable = visitor.preparable
|
63
|
+
if preparable.nil?
|
64
|
+
preparable = prepared_statements ? visitor.preparable : false
|
57
65
|
end
|
58
66
|
|
59
67
|
if prepared_statements && preparable
|
@@ -98,6 +106,11 @@ module ActiveRecord
|
|
98
106
|
exec_query(sql, name).rows
|
99
107
|
end
|
100
108
|
|
109
|
+
# Determines whether the SQL statement is a write query.
|
110
|
+
def write_query?(sql)
|
111
|
+
raise NotImplementedError
|
112
|
+
end
|
113
|
+
|
101
114
|
# Executes the SQL statement in the context of this connection and returns
|
102
115
|
# the raw result from the connection adapter.
|
103
116
|
# Note: depending on your database connector, the result returned by this
|
@@ -118,7 +131,7 @@ module ActiveRecord
|
|
118
131
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
119
132
|
# the executed +sql+ statement.
|
120
133
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
121
|
-
sql, binds = sql_for_insert(sql, pk,
|
134
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
122
135
|
exec_query(sql, name, binds)
|
123
136
|
end
|
124
137
|
|
@@ -129,11 +142,6 @@ module ActiveRecord
|
|
129
142
|
exec_query(sql, name, binds)
|
130
143
|
end
|
131
144
|
|
132
|
-
# Executes the truncate statement.
|
133
|
-
def truncate(table_name, name = nil)
|
134
|
-
raise NotImplementedError
|
135
|
-
end
|
136
|
-
|
137
145
|
# Executes update +sql+ statement in the context of this connection using
|
138
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
139
147
|
# the executed +sql+ statement.
|
@@ -141,6 +149,10 @@ module ActiveRecord
|
|
141
149
|
exec_query(sql, name, binds)
|
142
150
|
end
|
143
151
|
|
152
|
+
def exec_insert_all(sql, name) # :nodoc:
|
153
|
+
exec_query(sql, name)
|
154
|
+
end
|
155
|
+
|
144
156
|
# Executes an INSERT query and returns the new record's ID
|
145
157
|
#
|
146
158
|
# +id_value+ will be returned unless the value is +nil+, in
|
@@ -168,12 +180,22 @@ module ActiveRecord
|
|
168
180
|
exec_delete(sql, name, binds)
|
169
181
|
end
|
170
182
|
|
171
|
-
#
|
172
|
-
|
173
|
-
|
174
|
-
|
183
|
+
# Executes the truncate statement.
|
184
|
+
def truncate(table_name, name = nil)
|
185
|
+
execute(build_truncate_statements(table_name), name)
|
186
|
+
end
|
187
|
+
|
188
|
+
def truncate_tables(*table_names) # :nodoc:
|
189
|
+
return if table_names.empty?
|
190
|
+
|
191
|
+
with_multi_statements do
|
192
|
+
disable_referential_integrity do
|
193
|
+
Array(build_truncate_statements(*table_names)).each do |sql|
|
194
|
+
execute_batch(sql, "Truncate Tables")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
175
198
|
end
|
176
|
-
deprecate :supports_statement_cache?
|
177
199
|
|
178
200
|
# Runs the given block in a database transaction, and returns the result
|
179
201
|
# of the block.
|
@@ -264,7 +286,9 @@ module ActiveRecord
|
|
264
286
|
|
265
287
|
attr_reader :transaction_manager #:nodoc:
|
266
288
|
|
267
|
-
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
289
|
+
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
290
|
+
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
291
|
+
:disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
|
268
292
|
|
269
293
|
def transaction_open?
|
270
294
|
current_transaction.open?
|
@@ -329,68 +353,30 @@ module ActiveRecord
|
|
329
353
|
|
330
354
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
331
355
|
# something beyond a simple insert (eg. Oracle).
|
332
|
-
# Most of adapters should implement `
|
356
|
+
# Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
|
333
357
|
# We keep this method to provide fallback
|
334
358
|
# for databases like sqlite that do not support bulk inserts.
|
335
359
|
def insert_fixture(fixture, table_name)
|
336
|
-
fixture
|
337
|
-
|
338
|
-
columns = schema_cache.columns_hash(table_name)
|
339
|
-
binds = fixture.map do |name, value|
|
340
|
-
if column = columns[name]
|
341
|
-
type = lookup_cast_type_from_column(column)
|
342
|
-
Relation::QueryAttribute.new(name, value, type)
|
343
|
-
else
|
344
|
-
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
table = Arel::Table.new(table_name)
|
349
|
-
|
350
|
-
values = binds.map do |bind|
|
351
|
-
value = with_yaml_fallback(bind.value_for_database)
|
352
|
-
[table[bind.name], value]
|
353
|
-
end
|
354
|
-
|
355
|
-
manager = Arel::InsertManager.new
|
356
|
-
manager.into(table)
|
357
|
-
manager.insert(values)
|
358
|
-
execute manager.to_sql, "Fixture Insert"
|
359
|
-
end
|
360
|
-
|
361
|
-
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
362
|
-
# something beyond a simple insert (eg. Oracle).
|
363
|
-
def insert_fixtures(fixtures, table_name)
|
364
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
365
|
-
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
366
|
-
Consider using `insert_fixtures_set` for performance improvement.
|
367
|
-
MSG
|
368
|
-
return if fixtures.empty?
|
369
|
-
|
370
|
-
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
360
|
+
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
371
361
|
end
|
372
362
|
|
373
363
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
374
|
-
fixture_inserts = fixture_set
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
transaction(requires_new: true) do
|
385
|
-
total_sql.each do |sql|
|
386
|
-
execute sql, "Fixtures Load"
|
387
|
-
yield if block_given?
|
364
|
+
fixture_inserts = build_fixture_statements(fixture_set)
|
365
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
366
|
+
total_sql = Array(combine_multi_statements(table_deletes + fixture_inserts))
|
367
|
+
|
368
|
+
with_multi_statements do
|
369
|
+
disable_referential_integrity do
|
370
|
+
transaction(requires_new: true) do
|
371
|
+
total_sql.each do |sql|
|
372
|
+
execute_batch(sql, "Fixtures Load")
|
373
|
+
end
|
388
374
|
end
|
389
375
|
end
|
390
376
|
end
|
391
377
|
end
|
392
378
|
|
393
|
-
def empty_insert_statement_value
|
379
|
+
def empty_insert_statement_value(primary_key = nil)
|
394
380
|
"DEFAULT VALUES"
|
395
381
|
end
|
396
382
|
|
@@ -408,25 +394,33 @@ module ActiveRecord
|
|
408
394
|
end
|
409
395
|
end
|
410
396
|
|
411
|
-
#
|
412
|
-
#
|
413
|
-
#
|
414
|
-
def
|
415
|
-
|
416
|
-
|
417
|
-
|
397
|
+
# Fixture value is quoted by Arel, however scalar values
|
398
|
+
# are not quotable. In this case we want to convert
|
399
|
+
# the column value to YAML.
|
400
|
+
def with_yaml_fallback(value) # :nodoc:
|
401
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
402
|
+
YAML.dump(value)
|
403
|
+
else
|
404
|
+
value
|
405
|
+
end
|
418
406
|
end
|
419
|
-
alias join_to_delete join_to_update
|
420
407
|
|
421
408
|
private
|
409
|
+
def execute_batch(sql, name = nil)
|
410
|
+
execute(sql, name)
|
411
|
+
end
|
412
|
+
|
413
|
+
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
414
|
+
private_constant :DEFAULT_INSERT_VALUE
|
415
|
+
|
422
416
|
def default_insert_value(column)
|
423
|
-
|
417
|
+
DEFAULT_INSERT_VALUE
|
424
418
|
end
|
425
419
|
|
426
420
|
def build_fixture_sql(fixtures, table_name)
|
427
421
|
columns = schema_cache.columns_hash(table_name)
|
428
422
|
|
429
|
-
|
423
|
+
values_list = fixtures.map do |fixture|
|
430
424
|
fixture = fixture.stringify_keys
|
431
425
|
|
432
426
|
unknown_columns = fixture.keys - columns.keys
|
@@ -437,8 +431,7 @@ module ActiveRecord
|
|
437
431
|
columns.map do |name, column|
|
438
432
|
if fixture.key?(name)
|
439
433
|
type = lookup_cast_type_from_column(column)
|
440
|
-
|
441
|
-
with_yaml_fallback(bind.value_for_database)
|
434
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
442
435
|
else
|
443
436
|
default_insert_value(column)
|
444
437
|
end
|
@@ -448,21 +441,45 @@ module ActiveRecord
|
|
448
441
|
table = Arel::Table.new(table_name)
|
449
442
|
manager = Arel::InsertManager.new
|
450
443
|
manager.into(table)
|
451
|
-
columns.each_key { |column| manager.columns << table[column] }
|
452
|
-
manager.values = manager.create_values_list(values)
|
453
444
|
|
445
|
+
if values_list.size == 1
|
446
|
+
values = values_list.shift
|
447
|
+
new_values = []
|
448
|
+
columns.each_key.with_index { |column, i|
|
449
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
450
|
+
new_values << values[i]
|
451
|
+
manager.columns << table[column]
|
452
|
+
end
|
453
|
+
}
|
454
|
+
values_list << new_values
|
455
|
+
else
|
456
|
+
columns.each_key { |column| manager.columns << table[column] }
|
457
|
+
end
|
458
|
+
|
459
|
+
manager.values = manager.create_values_list(values_list)
|
454
460
|
manager.to_sql
|
455
461
|
end
|
456
462
|
|
457
|
-
def
|
458
|
-
|
463
|
+
def build_fixture_statements(fixture_set)
|
464
|
+
fixture_set.map do |table_name, fixtures|
|
465
|
+
next if fixtures.empty?
|
466
|
+
build_fixture_sql(fixtures, table_name)
|
467
|
+
end.compact
|
459
468
|
end
|
460
469
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
470
|
+
def build_truncate_statements(*table_names)
|
471
|
+
truncate_tables = table_names.map do |table_name|
|
472
|
+
"TRUNCATE TABLE #{quote_table_name(table_name)}"
|
473
|
+
end
|
474
|
+
combine_multi_statements(truncate_tables)
|
475
|
+
end
|
476
|
+
|
477
|
+
def with_multi_statements
|
478
|
+
yield
|
479
|
+
end
|
480
|
+
|
481
|
+
def combine_multi_statements(total_sql)
|
482
|
+
total_sql.join(";\n")
|
466
483
|
end
|
467
484
|
|
468
485
|
# Returns an ActiveRecord::Result instance.
|
@@ -474,7 +491,7 @@ module ActiveRecord
|
|
474
491
|
exec_query(sql, name, binds, prepare: true)
|
475
492
|
end
|
476
493
|
|
477
|
-
def sql_for_insert(sql, pk,
|
494
|
+
def sql_for_insert(sql, pk, binds)
|
478
495
|
[sql, binds]
|
479
496
|
end
|
480
497
|
|
@@ -494,39 +511,6 @@ module ActiveRecord
|
|
494
511
|
relation
|
495
512
|
end
|
496
513
|
end
|
497
|
-
|
498
|
-
# Fixture value is quoted by Arel, however scalar values
|
499
|
-
# are not quotable. In this case we want to convert
|
500
|
-
# the column value to YAML.
|
501
|
-
def with_yaml_fallback(value)
|
502
|
-
if value.is_a?(Hash) || value.is_a?(Array)
|
503
|
-
YAML.dump(value)
|
504
|
-
else
|
505
|
-
value
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
class PartialQueryCollector
|
510
|
-
def initialize
|
511
|
-
@parts = []
|
512
|
-
@binds = []
|
513
|
-
end
|
514
|
-
|
515
|
-
def <<(str)
|
516
|
-
@parts << str
|
517
|
-
self
|
518
|
-
end
|
519
|
-
|
520
|
-
def add_bind(obj)
|
521
|
-
@binds << obj
|
522
|
-
@parts << Arel::Nodes::BindParam.new(1)
|
523
|
-
self
|
524
|
-
end
|
525
|
-
|
526
|
-
def value
|
527
|
-
[@parts, @binds]
|
528
|
-
end
|
529
|
-
end
|
530
514
|
end
|
531
515
|
end
|
532
516
|
end
|