activerecord 5.2.8.1 → 6.0.6.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 +938 -573
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- 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 +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- 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 +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- 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/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +77 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- 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 +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.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 +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- 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 +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +108 -67
- data/lib/active_record/counter_cache.rb +8 -30
- 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 +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- 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 +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +80 -61
- 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 +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- 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/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +234 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- 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 +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +3 -5
- 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/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -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/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/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -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/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -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/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +113 -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
|
#
|
@@ -146,7 +167,6 @@ module ActiveRecord
|
|
146
167
|
end
|
147
168
|
|
148
169
|
private
|
149
|
-
|
150
170
|
def internal_poll(timeout)
|
151
171
|
no_wait_poll || (timeout && wait_poll(timeout))
|
152
172
|
end
|
@@ -185,7 +205,7 @@ module ActiveRecord
|
|
185
205
|
def wait_poll(timeout)
|
186
206
|
@num_waiting += 1
|
187
207
|
|
188
|
-
t0 =
|
208
|
+
t0 = Concurrent.monotonic_time
|
189
209
|
elapsed = 0
|
190
210
|
loop do
|
191
211
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -194,7 +214,7 @@ module ActiveRecord
|
|
194
214
|
|
195
215
|
return remove if any?
|
196
216
|
|
197
|
-
elapsed =
|
217
|
+
elapsed = Concurrent.monotonic_time - t0
|
198
218
|
if elapsed >= timeout
|
199
219
|
msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
|
200
220
|
[timeout, elapsed]
|
@@ -294,20 +314,55 @@ module ActiveRecord
|
|
294
314
|
@frequency = frequency
|
295
315
|
end
|
296
316
|
|
317
|
+
@mutex = Mutex.new
|
318
|
+
@pools = {}
|
319
|
+
@threads = {}
|
320
|
+
|
321
|
+
class << self
|
322
|
+
def register_pool(pool, frequency) # :nodoc:
|
323
|
+
@mutex.synchronize do
|
324
|
+
unless @threads[frequency]&.alive?
|
325
|
+
@threads[frequency] = spawn_thread(frequency)
|
326
|
+
end
|
327
|
+
@pools[frequency] ||= []
|
328
|
+
@pools[frequency] << WeakRef.new(pool)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
private
|
333
|
+
def spawn_thread(frequency)
|
334
|
+
Thread.new(frequency) do |t|
|
335
|
+
running = true
|
336
|
+
while running
|
337
|
+
sleep t
|
338
|
+
@mutex.synchronize do
|
339
|
+
@pools[frequency].select!(&:weakref_alive?)
|
340
|
+
@pools[frequency].each do |p|
|
341
|
+
p.reap
|
342
|
+
p.flush
|
343
|
+
rescue WeakRef::RefError
|
344
|
+
end
|
345
|
+
|
346
|
+
if @pools[frequency].empty?
|
347
|
+
@pools.delete(frequency)
|
348
|
+
@threads.delete(frequency)
|
349
|
+
running = false
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
297
357
|
def run
|
298
358
|
return unless frequency && frequency > 0
|
299
|
-
|
300
|
-
loop do
|
301
|
-
sleep t
|
302
|
-
p.reap
|
303
|
-
p.flush
|
304
|
-
end
|
305
|
-
}
|
359
|
+
self.class.register_pool(pool, frequency)
|
306
360
|
end
|
307
361
|
end
|
308
362
|
|
309
363
|
include MonitorMixin
|
310
364
|
include QueryCache::ConnectionPoolConfiguration
|
365
|
+
include ConnectionAdapters::AbstractPool
|
311
366
|
|
312
367
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
313
368
|
attr_reader :spec, :size, :reaper
|
@@ -593,6 +648,7 @@ module ActiveRecord
|
|
593
648
|
# or a thread dies unexpectedly.
|
594
649
|
def reap
|
595
650
|
stale_connections = synchronize do
|
651
|
+
return unless @connections
|
596
652
|
@connections.select do |conn|
|
597
653
|
conn.in_use? && !conn.owner.alive?
|
598
654
|
end.each do |conn|
|
@@ -617,6 +673,7 @@ module ActiveRecord
|
|
617
673
|
return if minimum_idle.nil?
|
618
674
|
|
619
675
|
idle_connections = synchronize do
|
676
|
+
return unless @connections
|
620
677
|
@connections.select do |conn|
|
621
678
|
!conn.in_use? && conn.seconds_idle >= minimum_idle
|
622
679
|
end.each do |conn|
|
@@ -705,13 +762,13 @@ module ActiveRecord
|
|
705
762
|
end
|
706
763
|
|
707
764
|
newly_checked_out = []
|
708
|
-
timeout_time =
|
765
|
+
timeout_time = Concurrent.monotonic_time + (@checkout_timeout * 2)
|
709
766
|
|
710
767
|
@available.with_a_bias_for(Thread.current) do
|
711
768
|
loop do
|
712
769
|
synchronize do
|
713
770
|
return if collected_conns.size == @connections.size && @now_connecting == 0
|
714
|
-
remaining_timeout = timeout_time -
|
771
|
+
remaining_timeout = timeout_time - Concurrent.monotonic_time
|
715
772
|
remaining_timeout = 0 if remaining_timeout < 0
|
716
773
|
conn = checkout_for_exclusive_access(remaining_timeout)
|
717
774
|
collected_conns << conn
|
@@ -750,7 +807,7 @@ module ActiveRecord
|
|
750
807
|
# this block can't be easily moved into attempt_to_checkout_all_existing_connections's
|
751
808
|
# rescue block, because doing so would put it outside of synchronize section, without
|
752
809
|
# being in a critical section thread_report might become inaccurate
|
753
|
-
msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
810
|
+
msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
|
754
811
|
|
755
812
|
thread_report = []
|
756
813
|
@connections.each do |conn|
|
@@ -828,7 +885,7 @@ module ActiveRecord
|
|
828
885
|
|
829
886
|
def new_connection
|
830
887
|
Base.send(spec.adapter_method, spec.config).tap do |conn|
|
831
|
-
conn.
|
888
|
+
conn.check_version
|
832
889
|
end
|
833
890
|
end
|
834
891
|
|
@@ -965,6 +1022,32 @@ module ActiveRecord
|
|
965
1022
|
ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
|
966
1023
|
end
|
967
1024
|
|
1025
|
+
def prevent_writes # :nodoc:
|
1026
|
+
Thread.current[:prevent_writes]
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
def prevent_writes=(prevent_writes) # :nodoc:
|
1030
|
+
Thread.current[:prevent_writes] = prevent_writes
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
# Prevent writing to the database regardless of role.
|
1034
|
+
#
|
1035
|
+
# In some cases you may want to prevent writes to the database
|
1036
|
+
# even if you are on a database that can write. `while_preventing_writes`
|
1037
|
+
# will prevent writes to the database for the duration of the block.
|
1038
|
+
#
|
1039
|
+
# This method does not provide the same protection as a readonly
|
1040
|
+
# user and is meant to be a safeguard against accidental writes.
|
1041
|
+
#
|
1042
|
+
# See `READ_QUERY` for the queries that are blocked by this
|
1043
|
+
# method.
|
1044
|
+
def while_preventing_writes(enabled = true)
|
1045
|
+
original, self.prevent_writes = self.prevent_writes, enabled
|
1046
|
+
yield
|
1047
|
+
ensure
|
1048
|
+
self.prevent_writes = original
|
1049
|
+
end
|
1050
|
+
|
968
1051
|
def connection_pool_list
|
969
1052
|
owner_to_pool.values.compact
|
970
1053
|
end
|
@@ -1029,15 +1112,24 @@ module ActiveRecord
|
|
1029
1112
|
# for (not necessarily the current class).
|
1030
1113
|
def retrieve_connection(spec_name) #:nodoc:
|
1031
1114
|
pool = retrieve_connection_pool(spec_name)
|
1032
|
-
|
1115
|
+
|
1116
|
+
unless pool
|
1117
|
+
# multiple database application
|
1118
|
+
if ActiveRecord::Base.connection_handler != ActiveRecord::Base.default_connection_handler
|
1119
|
+
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found for the '#{ActiveRecord::Base.current_role}' role."
|
1120
|
+
else
|
1121
|
+
raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found."
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1033
1125
|
pool.connection
|
1034
1126
|
end
|
1035
1127
|
|
1036
1128
|
# Returns true if a connection that's accessible to this class has
|
1037
1129
|
# already been opened.
|
1038
1130
|
def connected?(spec_name)
|
1039
|
-
|
1040
|
-
|
1131
|
+
pool = retrieve_connection_pool(spec_name)
|
1132
|
+
pool && pool.connected?
|
1041
1133
|
end
|
1042
1134
|
|
1043
1135
|
# Remove the connection for this class. This will close the active
|
@@ -1073,7 +1165,6 @@ module ActiveRecord
|
|
1073
1165
|
end
|
1074
1166
|
|
1075
1167
|
private
|
1076
|
-
|
1077
1168
|
def owner_to_pool
|
1078
1169
|
@owner_to_pool[Process.pid]
|
1079
1170
|
end
|
@@ -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
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
end
|
23
23
|
|
24
24
|
if prepared_statements
|
25
|
-
sql, binds = visitor.
|
25
|
+
sql, binds = visitor.compile(arel_or_sql_string.ast, collector)
|
26
26
|
|
27
27
|
if binds.length > bind_params_length
|
28
28
|
unprepared_statement do
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
else
|
34
|
-
sql = visitor.
|
34
|
+
sql = visitor.compile(arel_or_sql_string.ast, collector)
|
35
35
|
end
|
36
36
|
[sql.freeze, binds]
|
37
37
|
else
|
@@ -45,11 +45,11 @@ module ActiveRecord
|
|
45
45
|
# can be used to query the database repeatedly.
|
46
46
|
def cacheable_query(klass, arel) # :nodoc:
|
47
47
|
if prepared_statements
|
48
|
-
sql, binds = visitor.
|
48
|
+
sql, binds = visitor.compile(arel.ast, collector)
|
49
49
|
query = klass.query(sql)
|
50
50
|
else
|
51
|
-
collector =
|
52
|
-
parts, binds = visitor.
|
51
|
+
collector = klass.partial_query_collector
|
52
|
+
parts, binds = visitor.compile(arel.ast, collector)
|
53
53
|
query = klass.partial_query(parts)
|
54
54
|
end
|
55
55
|
[query, binds]
|
@@ -106,6 +106,11 @@ module ActiveRecord
|
|
106
106
|
exec_query(sql, name).rows
|
107
107
|
end
|
108
108
|
|
109
|
+
# Determines whether the SQL statement is a write query.
|
110
|
+
def write_query?(sql)
|
111
|
+
raise NotImplementedError
|
112
|
+
end
|
113
|
+
|
109
114
|
# Executes the SQL statement in the context of this connection and returns
|
110
115
|
# the raw result from the connection adapter.
|
111
116
|
# Note: depending on your database connector, the result returned by this
|
@@ -126,7 +131,7 @@ module ActiveRecord
|
|
126
131
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
127
132
|
# the executed +sql+ statement.
|
128
133
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
129
|
-
sql, binds = sql_for_insert(sql, pk,
|
134
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
130
135
|
exec_query(sql, name, binds)
|
131
136
|
end
|
132
137
|
|
@@ -137,11 +142,6 @@ module ActiveRecord
|
|
137
142
|
exec_query(sql, name, binds)
|
138
143
|
end
|
139
144
|
|
140
|
-
# Executes the truncate statement.
|
141
|
-
def truncate(table_name, name = nil)
|
142
|
-
raise NotImplementedError
|
143
|
-
end
|
144
|
-
|
145
145
|
# Executes update +sql+ statement in the context of this connection using
|
146
146
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
147
147
|
# the executed +sql+ statement.
|
@@ -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
|
@@ -176,12 +180,21 @@ module ActiveRecord
|
|
176
180
|
exec_delete(sql, name, binds)
|
177
181
|
end
|
178
182
|
|
179
|
-
#
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
+
# Executes the truncate statement.
|
184
|
+
def truncate(table_name, name = nil)
|
185
|
+
execute(build_truncate_statement(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
|
+
statements = build_truncate_statements(table_names)
|
194
|
+
execute_batch(statements, "Truncate Tables")
|
195
|
+
end
|
196
|
+
end
|
183
197
|
end
|
184
|
-
deprecate :supports_statement_cache?
|
185
198
|
|
186
199
|
# Runs the given block in a database transaction, and returns the result
|
187
200
|
# of the block.
|
@@ -272,7 +285,9 @@ module ActiveRecord
|
|
272
285
|
|
273
286
|
attr_reader :transaction_manager #:nodoc:
|
274
287
|
|
275
|
-
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
288
|
+
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
|
289
|
+
:commit_transaction, :rollback_transaction, :materialize_transactions,
|
290
|
+
:disable_lazy_transactions!, :enable_lazy_transactions!, to: :transaction_manager
|
276
291
|
|
277
292
|
def transaction_open?
|
278
293
|
current_transaction.open?
|
@@ -337,68 +352,28 @@ module ActiveRecord
|
|
337
352
|
|
338
353
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
339
354
|
# something beyond a simple insert (eg. Oracle).
|
340
|
-
# Most of adapters should implement `
|
355
|
+
# Most of adapters should implement `insert_fixtures_set` that leverages bulk SQL insert.
|
341
356
|
# We keep this method to provide fallback
|
342
357
|
# for databases like sqlite that do not support bulk inserts.
|
343
358
|
def insert_fixture(fixture, table_name)
|
344
|
-
fixture
|
345
|
-
|
346
|
-
columns = schema_cache.columns_hash(table_name)
|
347
|
-
binds = fixture.map do |name, value|
|
348
|
-
if column = columns[name]
|
349
|
-
type = lookup_cast_type_from_column(column)
|
350
|
-
Relation::QueryAttribute.new(name, value, type)
|
351
|
-
else
|
352
|
-
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
table = Arel::Table.new(table_name)
|
357
|
-
|
358
|
-
values = binds.map do |bind|
|
359
|
-
value = with_yaml_fallback(bind.value_for_database)
|
360
|
-
[table[bind.name], value]
|
361
|
-
end
|
362
|
-
|
363
|
-
manager = Arel::InsertManager.new
|
364
|
-
manager.into(table)
|
365
|
-
manager.insert(values)
|
366
|
-
execute manager.to_sql, "Fixture Insert"
|
367
|
-
end
|
368
|
-
|
369
|
-
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
370
|
-
# something beyond a simple insert (eg. Oracle).
|
371
|
-
def insert_fixtures(fixtures, table_name)
|
372
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
373
|
-
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
374
|
-
Consider using `insert_fixtures_set` for performance improvement.
|
375
|
-
MSG
|
376
|
-
return if fixtures.empty?
|
377
|
-
|
378
|
-
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
359
|
+
execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
|
379
360
|
end
|
380
361
|
|
381
362
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
382
|
-
fixture_inserts = fixture_set
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
disable_referential_integrity do
|
392
|
-
transaction(requires_new: true) do
|
393
|
-
total_sql.each do |sql|
|
394
|
-
execute sql, "Fixtures Load"
|
395
|
-
yield if block_given?
|
363
|
+
fixture_inserts = build_fixture_statements(fixture_set)
|
364
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
365
|
+
statements = table_deletes + fixture_inserts
|
366
|
+
|
367
|
+
with_multi_statements do
|
368
|
+
disable_referential_integrity do
|
369
|
+
transaction(requires_new: true) do
|
370
|
+
execute_batch(statements, "Fixtures Load")
|
396
371
|
end
|
397
372
|
end
|
398
373
|
end
|
399
374
|
end
|
400
375
|
|
401
|
-
def empty_insert_statement_value
|
376
|
+
def empty_insert_statement_value(primary_key = nil)
|
402
377
|
"DEFAULT VALUES"
|
403
378
|
end
|
404
379
|
|
@@ -416,25 +391,35 @@ module ActiveRecord
|
|
416
391
|
end
|
417
392
|
end
|
418
393
|
|
419
|
-
#
|
420
|
-
#
|
421
|
-
#
|
422
|
-
def
|
423
|
-
|
424
|
-
|
425
|
-
|
394
|
+
# Fixture value is quoted by Arel, however scalar values
|
395
|
+
# are not quotable. In this case we want to convert
|
396
|
+
# the column value to YAML.
|
397
|
+
def with_yaml_fallback(value) # :nodoc:
|
398
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
399
|
+
YAML.dump(value)
|
400
|
+
else
|
401
|
+
value
|
402
|
+
end
|
426
403
|
end
|
427
|
-
alias join_to_delete join_to_update
|
428
404
|
|
429
405
|
private
|
406
|
+
def execute_batch(statements, name = nil)
|
407
|
+
statements.each do |statement|
|
408
|
+
execute(statement, name)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
|
413
|
+
private_constant :DEFAULT_INSERT_VALUE
|
414
|
+
|
430
415
|
def default_insert_value(column)
|
431
|
-
|
416
|
+
DEFAULT_INSERT_VALUE
|
432
417
|
end
|
433
418
|
|
434
419
|
def build_fixture_sql(fixtures, table_name)
|
435
420
|
columns = schema_cache.columns_hash(table_name)
|
436
421
|
|
437
|
-
|
422
|
+
values_list = fixtures.map do |fixture|
|
438
423
|
fixture = fixture.stringify_keys
|
439
424
|
|
440
425
|
unknown_columns = fixture.keys - columns.keys
|
@@ -445,8 +430,7 @@ module ActiveRecord
|
|
445
430
|
columns.map do |name, column|
|
446
431
|
if fixture.key?(name)
|
447
432
|
type = lookup_cast_type_from_column(column)
|
448
|
-
|
449
|
-
with_yaml_fallback(bind.value_for_database)
|
433
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
450
434
|
else
|
451
435
|
default_insert_value(column)
|
452
436
|
end
|
@@ -456,21 +440,48 @@ module ActiveRecord
|
|
456
440
|
table = Arel::Table.new(table_name)
|
457
441
|
manager = Arel::InsertManager.new
|
458
442
|
manager.into(table)
|
459
|
-
columns.each_key { |column| manager.columns << table[column] }
|
460
|
-
manager.values = manager.create_values_list(values)
|
461
443
|
|
462
|
-
|
444
|
+
if values_list.size == 1
|
445
|
+
values = values_list.shift
|
446
|
+
new_values = []
|
447
|
+
columns.each_key.with_index { |column, i|
|
448
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
449
|
+
new_values << values[i]
|
450
|
+
manager.columns << table[column]
|
451
|
+
end
|
452
|
+
}
|
453
|
+
values_list << new_values
|
454
|
+
else
|
455
|
+
columns.each_key { |column| manager.columns << table[column] }
|
456
|
+
end
|
457
|
+
|
458
|
+
manager.values = manager.create_values_list(values_list)
|
459
|
+
visitor.compile(manager.ast)
|
463
460
|
end
|
464
461
|
|
465
|
-
def
|
466
|
-
|
462
|
+
def build_fixture_statements(fixture_set)
|
463
|
+
fixture_set.map do |table_name, fixtures|
|
464
|
+
next if fixtures.empty?
|
465
|
+
build_fixture_sql(fixtures, table_name)
|
466
|
+
end.compact
|
467
|
+
end
|
468
|
+
|
469
|
+
def build_truncate_statement(table_name)
|
470
|
+
"TRUNCATE TABLE #{quote_table_name(table_name)}"
|
471
|
+
end
|
472
|
+
|
473
|
+
def build_truncate_statements(table_names)
|
474
|
+
table_names.map do |table_name|
|
475
|
+
build_truncate_statement(table_name)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
def with_multi_statements
|
480
|
+
yield
|
467
481
|
end
|
468
482
|
|
469
|
-
|
470
|
-
|
471
|
-
subselect = select.clone
|
472
|
-
subselect.projections = [key]
|
473
|
-
subselect
|
483
|
+
def combine_multi_statements(total_sql)
|
484
|
+
total_sql.join(";\n")
|
474
485
|
end
|
475
486
|
|
476
487
|
# Returns an ActiveRecord::Result instance.
|
@@ -482,7 +493,7 @@ module ActiveRecord
|
|
482
493
|
exec_query(sql, name, binds, prepare: true)
|
483
494
|
end
|
484
495
|
|
485
|
-
def sql_for_insert(sql, pk,
|
496
|
+
def sql_for_insert(sql, pk, binds)
|
486
497
|
[sql, binds]
|
487
498
|
end
|
488
499
|
|
@@ -502,39 +513,6 @@ module ActiveRecord
|
|
502
513
|
relation
|
503
514
|
end
|
504
515
|
end
|
505
|
-
|
506
|
-
# Fixture value is quoted by Arel, however scalar values
|
507
|
-
# are not quotable. In this case we want to convert
|
508
|
-
# the column value to YAML.
|
509
|
-
def with_yaml_fallback(value)
|
510
|
-
if value.is_a?(Hash) || value.is_a?(Array)
|
511
|
-
YAML.dump(value)
|
512
|
-
else
|
513
|
-
value
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
class PartialQueryCollector
|
518
|
-
def initialize
|
519
|
-
@parts = []
|
520
|
-
@binds = []
|
521
|
-
end
|
522
|
-
|
523
|
-
def <<(str)
|
524
|
-
@parts << str
|
525
|
-
self
|
526
|
-
end
|
527
|
-
|
528
|
-
def add_bind(obj)
|
529
|
-
@binds << obj
|
530
|
-
@parts << Arel::Nodes::BindParam.new(1)
|
531
|
-
self
|
532
|
-
end
|
533
|
-
|
534
|
-
def value
|
535
|
-
[@parts, @binds]
|
536
|
-
end
|
537
|
-
end
|
538
516
|
end
|
539
517
|
end
|
540
518
|
end
|