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.

Files changed (294) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +938 -573
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +5 -3
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/advisory_lock_base.rb +18 -0
  7. data/lib/active_record/aggregations.rb +4 -3
  8. data/lib/active_record/association_relation.rb +10 -8
  9. data/lib/active_record/associations/alias_tracker.rb +0 -1
  10. data/lib/active_record/associations/association.rb +55 -19
  11. data/lib/active_record/associations/association_scope.rb +11 -7
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +19 -23
  22. data/lib/active_record/associations/collection_proxy.rb +14 -17
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -11
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
  30. data/lib/active_record/associations/join_dependency.rb +47 -30
  31. data/lib/active_record/associations/preloader/association.rb +61 -41
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/preloader.rb +44 -33
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/associations/through_association.rb +1 -1
  36. data/lib/active_record/associations.rb +21 -16
  37. data/lib/active_record/attribute_assignment.rb +7 -11
  38. data/lib/active_record/attribute_decorators.rb +0 -2
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
  40. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  41. data/lib/active_record/attribute_methods/primary_key.rb +15 -24
  42. data/lib/active_record/attribute_methods/query.rb +2 -3
  43. data/lib/active_record/attribute_methods/read.rb +15 -54
  44. data/lib/active_record/attribute_methods/serialization.rb +1 -2
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
  46. data/lib/active_record/attribute_methods/write.rb +17 -25
  47. data/lib/active_record/attribute_methods.rb +28 -100
  48. data/lib/active_record/attributes.rb +13 -1
  49. data/lib/active_record/autosave_association.rb +12 -14
  50. data/lib/active_record/base.rb +2 -3
  51. data/lib/active_record/callbacks.rb +6 -21
  52. data/lib/active_record/coders/yaml_column.rb +15 -6
  53. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
  54. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  55. data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
  56. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
  57. data/lib/active_record/connection_adapters/abstract/quoting.rb +77 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
  59. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
  60. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
  62. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
  63. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
  64. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
  65. data/lib/active_record/connection_adapters/column.rb +17 -13
  66. data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
  67. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  68. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
  70. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
  71. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  72. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
  73. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  74. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  75. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  76. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  89. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
  98. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
  101. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  102. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
  107. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  108. data/lib/active_record/connection_handling.rb +139 -26
  109. data/lib/active_record/core.rb +108 -67
  110. data/lib/active_record/counter_cache.rb +8 -30
  111. data/lib/active_record/database_configurations/database_config.rb +37 -0
  112. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  113. data/lib/active_record/database_configurations/url_config.rb +78 -0
  114. data/lib/active_record/database_configurations.rb +233 -0
  115. data/lib/active_record/dynamic_matchers.rb +3 -4
  116. data/lib/active_record/enum.rb +44 -7
  117. data/lib/active_record/errors.rb +15 -7
  118. data/lib/active_record/explain.rb +1 -2
  119. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  120. data/lib/active_record/fixture_set/render_context.rb +17 -0
  121. data/lib/active_record/fixture_set/table_row.rb +152 -0
  122. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  123. data/lib/active_record/fixtures.rb +144 -474
  124. data/lib/active_record/gem_version.rb +3 -3
  125. data/lib/active_record/inheritance.rb +13 -6
  126. data/lib/active_record/insert_all.rb +179 -0
  127. data/lib/active_record/integration.rb +68 -16
  128. data/lib/active_record/internal_metadata.rb +11 -3
  129. data/lib/active_record/locking/optimistic.rb +14 -7
  130. data/lib/active_record/locking/pessimistic.rb +3 -3
  131. data/lib/active_record/log_subscriber.rb +8 -27
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
  134. data/lib/active_record/middleware/database_selector.rb +74 -0
  135. data/lib/active_record/migration/command_recorder.rb +54 -22
  136. data/lib/active_record/migration/compatibility.rb +79 -52
  137. data/lib/active_record/migration/join_table.rb +0 -1
  138. data/lib/active_record/migration.rb +104 -85
  139. data/lib/active_record/model_schema.rb +62 -11
  140. data/lib/active_record/nested_attributes.rb +2 -4
  141. data/lib/active_record/no_touching.rb +9 -2
  142. data/lib/active_record/null_relation.rb +0 -1
  143. data/lib/active_record/persistence.rb +232 -29
  144. data/lib/active_record/query_cache.rb +11 -4
  145. data/lib/active_record/querying.rb +33 -21
  146. data/lib/active_record/railtie.rb +80 -61
  147. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  148. data/lib/active_record/railties/controller_runtime.rb +30 -35
  149. data/lib/active_record/railties/databases.rake +199 -46
  150. data/lib/active_record/reflection.rb +51 -51
  151. data/lib/active_record/relation/batches.rb +13 -11
  152. data/lib/active_record/relation/calculations.rb +55 -49
  153. data/lib/active_record/relation/delegation.rb +35 -50
  154. data/lib/active_record/relation/finder_methods.rb +23 -28
  155. data/lib/active_record/relation/from_clause.rb +4 -0
  156. data/lib/active_record/relation/merger.rb +12 -17
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  159. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  160. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  161. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  162. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  163. data/lib/active_record/relation/predicate_builder.rb +5 -11
  164. data/lib/active_record/relation/query_attribute.rb +13 -8
  165. data/lib/active_record/relation/query_methods.rb +234 -69
  166. data/lib/active_record/relation/spawn_methods.rb +1 -2
  167. data/lib/active_record/relation/where_clause.rb +14 -11
  168. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  169. data/lib/active_record/relation.rb +326 -81
  170. data/lib/active_record/result.rb +30 -12
  171. data/lib/active_record/sanitization.rb +32 -40
  172. data/lib/active_record/schema.rb +2 -11
  173. data/lib/active_record/schema_dumper.rb +22 -7
  174. data/lib/active_record/schema_migration.rb +6 -2
  175. data/lib/active_record/scoping/default.rb +4 -6
  176. data/lib/active_record/scoping/named.rb +25 -16
  177. data/lib/active_record/scoping.rb +8 -9
  178. data/lib/active_record/statement_cache.rb +30 -3
  179. data/lib/active_record/store.rb +87 -8
  180. data/lib/active_record/suppressor.rb +2 -2
  181. data/lib/active_record/table_metadata.rb +23 -15
  182. data/lib/active_record/tasks/database_tasks.rb +194 -25
  183. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
  184. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
  185. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
  186. data/lib/active_record/test_databases.rb +23 -0
  187. data/lib/active_record/test_fixtures.rb +243 -0
  188. data/lib/active_record/timestamp.rb +39 -26
  189. data/lib/active_record/touch_later.rb +5 -4
  190. data/lib/active_record/transactions.rb +64 -73
  191. data/lib/active_record/translation.rb +1 -1
  192. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  193. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  194. data/lib/active_record/type/serialized.rb +0 -1
  195. data/lib/active_record/type/time.rb +10 -0
  196. data/lib/active_record/type/type_map.rb +0 -1
  197. data/lib/active_record/type/unsigned_integer.rb +0 -1
  198. data/lib/active_record/type.rb +3 -5
  199. data/lib/active_record/type_caster/connection.rb +15 -14
  200. data/lib/active_record/type_caster/map.rb +1 -4
  201. data/lib/active_record/validations/associated.rb +0 -1
  202. data/lib/active_record/validations/uniqueness.rb +15 -27
  203. data/lib/active_record/validations.rb +3 -3
  204. data/lib/active_record.rb +10 -2
  205. data/lib/arel/alias_predication.rb +9 -0
  206. data/lib/arel/attributes/attribute.rb +37 -0
  207. data/lib/arel/attributes.rb +22 -0
  208. data/lib/arel/collectors/bind.rb +24 -0
  209. data/lib/arel/collectors/composite.rb +31 -0
  210. data/lib/arel/collectors/plain_string.rb +20 -0
  211. data/lib/arel/collectors/sql_string.rb +20 -0
  212. data/lib/arel/collectors/substitute_binds.rb +28 -0
  213. data/lib/arel/crud.rb +42 -0
  214. data/lib/arel/delete_manager.rb +18 -0
  215. data/lib/arel/errors.rb +9 -0
  216. data/lib/arel/expressions.rb +29 -0
  217. data/lib/arel/factory_methods.rb +49 -0
  218. data/lib/arel/insert_manager.rb +49 -0
  219. data/lib/arel/math.rb +45 -0
  220. data/lib/arel/nodes/and.rb +32 -0
  221. data/lib/arel/nodes/ascending.rb +23 -0
  222. data/lib/arel/nodes/binary.rb +52 -0
  223. data/lib/arel/nodes/bind_param.rb +36 -0
  224. data/lib/arel/nodes/case.rb +55 -0
  225. data/lib/arel/nodes/casted.rb +50 -0
  226. data/lib/arel/nodes/comment.rb +29 -0
  227. data/lib/arel/nodes/count.rb +12 -0
  228. data/lib/arel/nodes/delete_statement.rb +45 -0
  229. data/lib/arel/nodes/descending.rb +23 -0
  230. data/lib/arel/nodes/equality.rb +18 -0
  231. data/lib/arel/nodes/extract.rb +24 -0
  232. data/lib/arel/nodes/false.rb +16 -0
  233. data/lib/arel/nodes/full_outer_join.rb +8 -0
  234. data/lib/arel/nodes/function.rb +44 -0
  235. data/lib/arel/nodes/grouping.rb +8 -0
  236. data/lib/arel/nodes/in.rb +8 -0
  237. data/lib/arel/nodes/infix_operation.rb +80 -0
  238. data/lib/arel/nodes/inner_join.rb +8 -0
  239. data/lib/arel/nodes/insert_statement.rb +37 -0
  240. data/lib/arel/nodes/join_source.rb +20 -0
  241. data/lib/arel/nodes/matches.rb +18 -0
  242. data/lib/arel/nodes/named_function.rb +23 -0
  243. data/lib/arel/nodes/node.rb +50 -0
  244. data/lib/arel/nodes/node_expression.rb +13 -0
  245. data/lib/arel/nodes/outer_join.rb +8 -0
  246. data/lib/arel/nodes/over.rb +15 -0
  247. data/lib/arel/nodes/regexp.rb +16 -0
  248. data/lib/arel/nodes/right_outer_join.rb +8 -0
  249. data/lib/arel/nodes/select_core.rb +67 -0
  250. data/lib/arel/nodes/select_statement.rb +41 -0
  251. data/lib/arel/nodes/sql_literal.rb +16 -0
  252. data/lib/arel/nodes/string_join.rb +11 -0
  253. data/lib/arel/nodes/table_alias.rb +27 -0
  254. data/lib/arel/nodes/terminal.rb +16 -0
  255. data/lib/arel/nodes/true.rb +16 -0
  256. data/lib/arel/nodes/unary.rb +45 -0
  257. data/lib/arel/nodes/unary_operation.rb +20 -0
  258. data/lib/arel/nodes/unqualified_column.rb +22 -0
  259. data/lib/arel/nodes/update_statement.rb +41 -0
  260. data/lib/arel/nodes/values_list.rb +9 -0
  261. data/lib/arel/nodes/window.rb +126 -0
  262. data/lib/arel/nodes/with.rb +11 -0
  263. data/lib/arel/nodes.rb +68 -0
  264. data/lib/arel/order_predications.rb +13 -0
  265. data/lib/arel/predications.rb +256 -0
  266. data/lib/arel/select_manager.rb +271 -0
  267. data/lib/arel/table.rb +110 -0
  268. data/lib/arel/tree_manager.rb +72 -0
  269. data/lib/arel/update_manager.rb +34 -0
  270. data/lib/arel/visitors/depth_first.rb +203 -0
  271. data/lib/arel/visitors/dot.rb +296 -0
  272. data/lib/arel/visitors/ibm_db.rb +34 -0
  273. data/lib/arel/visitors/informix.rb +62 -0
  274. data/lib/arel/visitors/mssql.rb +156 -0
  275. data/lib/arel/visitors/mysql.rb +83 -0
  276. data/lib/arel/visitors/oracle.rb +158 -0
  277. data/lib/arel/visitors/oracle12.rb +65 -0
  278. data/lib/arel/visitors/postgresql.rb +109 -0
  279. data/lib/arel/visitors/sqlite.rb +38 -0
  280. data/lib/arel/visitors/to_sql.rb +888 -0
  281. data/lib/arel/visitors/visitor.rb +45 -0
  282. data/lib/arel/visitors/where_sql.rb +22 -0
  283. data/lib/arel/visitors.rb +20 -0
  284. data/lib/arel/window_predications.rb +9 -0
  285. data/lib/arel.rb +62 -0
  286. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  287. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  288. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  289. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  290. data/lib/rails/generators/active_record/migration.rb +14 -2
  291. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  292. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  293. metadata +113 -26
  294. 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 = Time.now
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 = Time.now - t0
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
- Thread.new(frequency, pool) { |t, p|
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 = Time.now + (@checkout_timeout * 2)
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 - Time.now
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".dup
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.schema_cache = schema_cache.dup if schema_cache
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
- raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
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
- conn = retrieve_connection_pool(spec_name)
1040
- conn && conn.connected?
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
- 255
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
- 64
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
- 64
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
- 64
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.accept(arel_or_sql_string.ast, collector).value
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.accept(arel_or_sql_string.ast, collector).value
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.accept(arel.ast, collector).value
48
+ sql, binds = visitor.compile(arel.ast, collector)
49
49
  query = klass.query(sql)
50
50
  else
51
- collector = PartialQueryCollector.new
52
- parts, binds = visitor.accept(arel.ast, collector).value
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, nil, sequence_name, binds)
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
- # Returns +true+ when the connection adapter supports prepared statement
180
- # caching, otherwise returns +false+
181
- def supports_statement_cache? # :nodoc:
182
- true
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, :commit_transaction, :rollback_transaction, to: :transaction_manager
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 `insert_fixtures` that leverages bulk SQL insert.
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 = fixture.stringify_keys
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.map do |table_name, fixtures|
383
- next if fixtures.empty?
384
-
385
- build_fixture_sql(fixtures, table_name)
386
- end.compact
387
-
388
- table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
389
- total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
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
- # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
420
- # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
421
- # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
422
- def join_to_update(update, select, key) # :nodoc:
423
- subselect = subquery_for(key, select)
424
-
425
- update.where key.in(subselect)
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
- Arel.sql("DEFAULT")
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
- values = fixtures.map do |fixture|
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
- bind = Relation::QueryAttribute.new(name, fixture[name], type)
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
- manager.to_sql
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 combine_multi_statements(total_sql)
466
- total_sql.join(";\n")
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
- # Returns a subquery for the given key using the join information.
470
- def subquery_for(key, select)
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, id_value, sequence_name, binds)
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