activerecord 6.0.0 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  end
37
37
 
38
38
  if row[:Expression]
39
- expression = row[:Expression]
39
+ expression = row[:Expression].gsub("\\'", "'")
40
40
  expression = +"(#{expression})" unless expression.start_with?("(")
41
41
  indexes.last[-2] << expression
42
42
  indexes.last[-1][:expressions] ||= {}
@@ -51,26 +51,32 @@ module ActiveRecord
51
51
  end
52
52
 
53
53
  indexes.map do |index|
54
- options = index.last
54
+ options = index.pop
55
55
 
56
56
  if expressions = options.delete(:expressions)
57
57
  orders = options.delete(:orders)
58
58
  lengths = options.delete(:lengths)
59
59
 
60
- columns = index[-2].map { |name|
60
+ columns = index[-1].to_h { |name|
61
61
  [ name.to_sym, expressions[name] || +quote_column_name(name) ]
62
- }.to_h
62
+ }
63
63
 
64
- index[-2] = add_options_for_index_columns(
64
+ index[-1] = add_options_for_index_columns(
65
65
  columns, order: orders, length: lengths
66
66
  ).values.join(", ")
67
67
  end
68
68
 
69
- IndexDefinition.new(*index)
69
+ IndexDefinition.new(*index, **options)
70
+ end
71
+ rescue StatementInvalid => e
72
+ if e.message.match?(/Table '.+' doesn't exist/)
73
+ []
74
+ else
75
+ raise
70
76
  end
71
77
  end
72
78
 
73
- def remove_column(table_name, column_name, type = nil, options = {})
79
+ def remove_column(table_name, column_name, type = nil, **options)
74
80
  if foreign_key_exists?(table_name, column: column_name)
75
81
  remove_foreign_key(table_name, column: column_name)
76
82
  end
@@ -122,7 +128,11 @@ module ActiveRecord
122
128
  end
123
129
 
124
130
  def table_alias_length
125
- 256 # https://dev.mysql.com/doc/refman/8.0/en/identifiers.html
131
+ 256 # https://dev.mysql.com/doc/refman/en/identifiers.html
132
+ end
133
+
134
+ def schema_creation # :nodoc:
135
+ MySQL::SchemaCreation.new(self)
126
136
  end
127
137
 
128
138
  private
@@ -150,22 +160,45 @@ module ActiveRecord
150
160
  @default_row_format
151
161
  end
152
162
 
153
- def schema_creation
154
- MySQL::SchemaCreation.new(self)
163
+ def valid_primary_key_options
164
+ super + [:unsigned, :auto_increment]
155
165
  end
156
166
 
157
- def create_table_definition(*args)
158
- MySQL::TableDefinition.new(self, *args)
167
+ def create_table_definition(name, **options)
168
+ MySQL::TableDefinition.new(self, name, **options)
159
169
  end
160
170
 
161
- def new_column_from_field(table_name, field)
171
+ def default_type(table_name, field_name)
172
+ match = create_table_info(table_name)&.match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
173
+ default_pre = match[2] if match
174
+
175
+ if default_pre == "'"
176
+ :string
177
+ elsif default_pre&.match?(/^\d+$/)
178
+ :integer
179
+ elsif default_pre&.match?(/^[A-z]+$/)
180
+ :function
181
+ end
182
+ end
183
+
184
+ def new_column_from_field(table_name, field, _definitions)
185
+ field_name = field.fetch(:Field)
162
186
  type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
163
187
  default, default_function = field[:Default], nil
164
188
 
165
189
  if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
190
+ default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
166
191
  default, default_function = nil, default
167
192
  elsif type_metadata.extra == "DEFAULT_GENERATED"
168
193
  default = +"(#{default})" unless default.start_with?("(")
194
+ default = default.gsub("\\'", "'")
195
+ default, default_function = nil, default
196
+ elsif type_metadata.type == :text && default&.start_with?("'")
197
+ # strip and unescape quotes
198
+ default = default[1...-1].gsub("\\'", "'")
199
+ elsif default&.match?(/\A\d/)
200
+ # Its a number so we can skip the query to check if it is a function
201
+ elsif default && default_type(table_name, field_name) == :function
169
202
  default, default_function = nil, default
170
203
  end
171
204
 
@@ -196,7 +229,7 @@ module ActiveRecord
196
229
  end
197
230
 
198
231
  def add_options_for_index_columns(quoted_columns, **options)
199
- quoted_columns = add_index_length(quoted_columns, options)
232
+ quoted_columns = add_index_length(quoted_columns, **options)
200
233
  super
201
234
  end
202
235
 
@@ -205,7 +238,12 @@ module ActiveRecord
205
238
 
206
239
  sql = +"SELECT table_name FROM information_schema.tables"
207
240
  sql << " WHERE table_schema = #{scope[:schema]}"
208
- sql << " AND table_name = #{scope[:name]}" if scope[:name]
241
+
242
+ if scope[:name]
243
+ sql << " AND table_name = #{scope[:name]}"
244
+ sql << " AND table_name IN (SELECT table_name FROM information_schema.tables WHERE table_schema = #{scope[:schema]})"
245
+ end
246
+
209
247
  sql << " AND table_type = #{scope[:type]}" if scope[:type]
210
248
  sql
211
249
  end
@@ -6,9 +6,11 @@ module ActiveRecord
6
6
  class TypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
7
7
  undef to_yaml if method_defined?(:to_yaml)
8
8
 
9
+ include Deduplicable
10
+
9
11
  attr_reader :extra
10
12
 
11
- def initialize(type_metadata, extra: "")
13
+ def initialize(type_metadata, extra: nil)
12
14
  super(type_metadata)
13
15
  @extra = extra
14
16
  end
@@ -25,6 +27,13 @@ module ActiveRecord
25
27
  __getobj__.hash ^
26
28
  extra.hash
27
29
  end
30
+
31
+ private
32
+ def deduplicated
33
+ __setobj__(__getobj__.deduplicate)
34
+ @extra = -extra if extra
35
+ super
36
+ end
28
37
  end
29
38
  end
30
39
  end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module Mysql2
6
+ module DatabaseStatements
7
+ # Returns an ActiveRecord::Result instance.
8
+ def select_all(*, **) # :nodoc:
9
+ if ExplainRegistry.collect? && prepared_statements
10
+ unprepared_statement { super }
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
17
+ if without_prepared_statement?(binds)
18
+ execute_and_free(sql, name, async: async, allow_retry: allow_retry) do |result|
19
+ if result
20
+ build_result(columns: result.fields, rows: result.to_a)
21
+ else
22
+ build_result(columns: [], rows: [])
23
+ end
24
+ end
25
+ else
26
+ exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async, allow_retry: allow_retry) do |_, result|
27
+ if result
28
+ build_result(columns: result.fields, rows: result.to_a)
29
+ else
30
+ build_result(columns: [], rows: [])
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def exec_delete(sql, name = nil, binds = []) # :nodoc:
37
+ if without_prepared_statement?(binds)
38
+ with_raw_connection do |conn|
39
+ @affected_rows_before_warnings = nil
40
+ execute_and_free(sql, name) { @affected_rows_before_warnings || conn.affected_rows }
41
+ end
42
+ else
43
+ exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
44
+ end
45
+ end
46
+ alias :exec_update :exec_delete
47
+
48
+ private
49
+ def sync_timezone_changes(raw_connection)
50
+ raw_connection.query_options[:database_timezone] = default_timezone
51
+ end
52
+
53
+ def execute_batch(statements, name = nil)
54
+ statements = statements.map { |sql| transform_query(sql) }
55
+ combine_multi_statements(statements).each do |statement|
56
+ with_raw_connection do |conn|
57
+ raw_execute(statement, name)
58
+ end
59
+ end
60
+ end
61
+
62
+ def last_inserted_id(result)
63
+ if supports_insert_returning?
64
+ super
65
+ else
66
+ @raw_connection&.last_id
67
+ end
68
+ end
69
+
70
+ def multi_statements_enabled?
71
+ flags = @config[:flags]
72
+
73
+ if flags.is_a?(Array)
74
+ flags.include?("MULTI_STATEMENTS")
75
+ else
76
+ flags.anybits?(::Mysql2::Client::MULTI_STATEMENTS)
77
+ end
78
+ end
79
+
80
+ def with_multi_statements
81
+ if multi_statements_enabled?
82
+ return yield
83
+ end
84
+
85
+ with_raw_connection do |conn|
86
+ conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
87
+
88
+ yield
89
+ ensure
90
+ conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
91
+ end
92
+ end
93
+
94
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
95
+ log(sql, name, async: async) do |notification_payload|
96
+ with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
97
+ sync_timezone_changes(conn)
98
+ result = conn.query(sql)
99
+ conn.abandon_results!
100
+ verified!
101
+ handle_warnings(sql)
102
+ notification_payload[:row_count] = result&.size || 0
103
+ result
104
+ end
105
+ end
106
+ end
107
+
108
+ def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false, allow_retry: false)
109
+ sql = transform_query(sql)
110
+ check_if_write_query(sql)
111
+
112
+ mark_transaction_written_if_write(sql)
113
+
114
+ type_casted_binds = type_casted_binds(binds)
115
+
116
+ log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
117
+ with_raw_connection(allow_retry: allow_retry) do |conn|
118
+ sync_timezone_changes(conn)
119
+
120
+ if cache_stmt
121
+ stmt = @statements[sql] ||= conn.prepare(sql)
122
+ else
123
+ stmt = conn.prepare(sql)
124
+ end
125
+
126
+ begin
127
+ result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
128
+ stmt.execute(*type_casted_binds)
129
+ end
130
+ verified!
131
+ result
132
+ rescue ::Mysql2::Error => e
133
+ if cache_stmt
134
+ @statements.delete(sql)
135
+ else
136
+ stmt.close
137
+ end
138
+ raise e
139
+ end
140
+
141
+ ret = yield stmt, result
142
+ notification_payload[:row_count] = result&.size || 0
143
+ result.free if result
144
+ stmt.close unless cache_stmt
145
+ ret
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -1,53 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record/connection_adapters/abstract_mysql_adapter"
4
- require "active_record/connection_adapters/mysql/database_statements"
4
+ require "active_record/connection_adapters/mysql2/database_statements"
5
5
 
6
- gem "mysql2", ">= 0.4.4"
6
+ gem "mysql2", "~> 0.5"
7
7
  require "mysql2"
8
8
 
9
9
  module ActiveRecord
10
- module ConnectionHandling # :nodoc:
11
- ER_BAD_DB_ERROR = 1049
12
-
13
- # Establishes a connection to the database that's used by all Active Record objects.
14
- def mysql2_connection(config)
15
- config = config.symbolize_keys
16
- config[:flags] ||= 0
17
-
18
- if config[:flags].kind_of? Array
19
- config[:flags].push "FOUND_ROWS"
20
- else
21
- config[:flags] |= Mysql2::Client::FOUND_ROWS
22
- end
23
-
24
- client = Mysql2::Client.new(config)
25
- ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
26
- rescue Mysql2::Error => error
27
- if error.error_number == ER_BAD_DB_ERROR
28
- raise ActiveRecord::NoDatabaseError
29
- else
30
- raise
31
- end
32
- end
33
- end
34
-
35
10
  module ConnectionAdapters
11
+ # = Active Record MySQL2 Adapter
36
12
  class Mysql2Adapter < AbstractMysqlAdapter
13
+ ER_BAD_DB_ERROR = 1049
14
+ ER_DBACCESS_DENIED_ERROR = 1044
15
+ ER_ACCESS_DENIED_ERROR = 1045
16
+ ER_CONN_HOST_ERROR = 2003
17
+ ER_UNKNOWN_HOST_ERROR = 2005
18
+
37
19
  ADAPTER_NAME = "Mysql2"
38
20
 
39
- include MySQL::DatabaseStatements
21
+ include Mysql2::DatabaseStatements
22
+
23
+ class << self
24
+ def new_client(config)
25
+ ::Mysql2::Client.new(config)
26
+ rescue ::Mysql2::Error => error
27
+ case error.error_number
28
+ when ER_BAD_DB_ERROR
29
+ raise ActiveRecord::NoDatabaseError.db_error(config[:database])
30
+ when ER_DBACCESS_DENIED_ERROR, ER_ACCESS_DENIED_ERROR
31
+ raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
32
+ when ER_CONN_HOST_ERROR, ER_UNKNOWN_HOST_ERROR
33
+ raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
34
+ else
35
+ raise ActiveRecord::ConnectionNotEstablished, error.message
36
+ end
37
+ end
38
+
39
+ private
40
+ def initialize_type_map(m)
41
+ super
40
42
 
41
- def initialize(connection, logger, connection_options, config)
42
- superclass_config = config.reverse_merge(prepared_statements: false)
43
- super(connection, logger, connection_options, superclass_config)
44
- configure_connection
43
+ m.register_type(%r(char)i) do |sql_type|
44
+ limit = extract_limit(sql_type)
45
+ Type.lookup(:string, adapter: :mysql2, limit: limit)
46
+ end
47
+
48
+ m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
49
+ m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
50
+ end
45
51
  end
46
52
 
47
- def self.database_exists?(config)
48
- !!ActiveRecord::Base.mysql2_connection(config)
49
- rescue ActiveRecord::NoDatabaseError
50
- false
53
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
54
+
55
+ def initialize(...)
56
+ super
57
+
58
+ @config[:flags] ||= 0
59
+
60
+ if @config[:flags].kind_of? Array
61
+ @config[:flags].push "FOUND_ROWS"
62
+ else
63
+ @config[:flags] |= ::Mysql2::Client::FOUND_ROWS
64
+ end
65
+
66
+ @connection_parameters ||= @config
51
67
  end
52
68
 
53
69
  def supports_json?
@@ -66,17 +82,19 @@ module ActiveRecord
66
82
  true
67
83
  end
68
84
 
85
+ def savepoint_errors_invalidate_transactions?
86
+ true
87
+ end
88
+
69
89
  def supports_lazy_transactions?
70
90
  true
71
91
  end
72
92
 
73
93
  # HELPER METHODS ===========================================
74
94
 
75
- def each_hash(result) # :nodoc:
95
+ def each_hash(result, &block) # :nodoc:
76
96
  if block_given?
77
- result.each(as: :hash, symbolize_keys: true) do |row|
78
- yield row
79
- end
97
+ result.each(as: :hash, symbolize_keys: true, &block)
80
98
  else
81
99
  to_enum(:each_hash, result)
82
100
  end
@@ -87,60 +105,106 @@ module ActiveRecord
87
105
  end
88
106
 
89
107
  #--
90
- # QUOTING ==================================================
108
+ # CONNECTION MANAGEMENT ====================================
91
109
  #++
92
110
 
93
- def quote_string(string)
94
- @connection.escape(string)
111
+ def connected?
112
+ !(@raw_connection.nil? || @raw_connection.closed?)
95
113
  end
96
114
 
97
- #--
98
- # CONNECTION MANAGEMENT ====================================
99
- #++
100
-
101
115
  def active?
102
- @connection.ping
116
+ if connected?
117
+ @lock.synchronize do
118
+ if @raw_connection&.ping
119
+ verified!
120
+ true
121
+ end
122
+ end
123
+ end || false
103
124
  end
104
125
 
105
- def reconnect!
106
- super
107
- disconnect!
108
- connect
109
- end
110
126
  alias :reset! :reconnect!
111
127
 
112
128
  # Disconnects from the database if already connected.
113
129
  # Otherwise, this method does nothing.
114
130
  def disconnect!
115
- super
116
- @connection.close
131
+ @lock.synchronize do
132
+ super
133
+ @raw_connection&.close
134
+ @raw_connection = nil
135
+ end
117
136
  end
118
137
 
119
138
  def discard! # :nodoc:
120
- super
121
- @connection.automatic_close = false
122
- @connection = nil
139
+ @lock.synchronize do
140
+ super
141
+ @raw_connection&.automatic_close = false
142
+ @raw_connection = nil
143
+ end
123
144
  end
124
145
 
125
146
  private
147
+ def text_type?(type)
148
+ TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
149
+ end
126
150
 
127
151
  def connect
128
- @connection = Mysql2::Client.new(@config)
129
- configure_connection
152
+ @raw_connection = self.class.new_client(@connection_parameters)
153
+ rescue ConnectionNotEstablished => ex
154
+ raise ex.set_pool(@pool)
155
+ end
156
+
157
+ def reconnect
158
+ @lock.synchronize do
159
+ @raw_connection&.close
160
+ @raw_connection = nil
161
+ connect
162
+ end
130
163
  end
131
164
 
132
165
  def configure_connection
133
- @connection.query_options[:as] = :array
166
+ @raw_connection.query_options[:as] = :array
167
+ @raw_connection.query_options[:database_timezone] = default_timezone
134
168
  super
135
169
  end
136
170
 
137
171
  def full_version
138
- schema_cache.database_version.full_version_string
172
+ database_version.full_version_string
139
173
  end
140
174
 
141
175
  def get_full_version
142
- @connection.server_info[:version]
176
+ any_raw_connection.server_info[:version]
177
+ end
178
+
179
+ def translate_exception(exception, message:, sql:, binds:)
180
+ if exception.is_a?(::Mysql2::Error::TimeoutError) && !exception.error_number
181
+ ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
182
+ elsif exception.is_a?(::Mysql2::Error::ConnectionError)
183
+ if exception.message.match?(/MySQL client is not connected/i)
184
+ ActiveRecord::ConnectionNotEstablished.new(exception, connection_pool: @pool)
185
+ else
186
+ ActiveRecord::ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
187
+ end
188
+ else
189
+ super
190
+ end
191
+ end
192
+
193
+ def default_prepared_statements
194
+ false
143
195
  end
196
+
197
+ ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
198
+ Type::ImmutableString.new(true: "1", false: "0", **args)
199
+ end
200
+
201
+ ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
202
+ Type::String.new(true: "1", false: "0", **args)
203
+ end
204
+
205
+ ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
144
206
  end
207
+
208
+ ActiveSupport.run_load_hooks(:active_record_mysql2adapter, Mysql2Adapter)
145
209
  end
146
210
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class PoolConfig # :nodoc:
6
+ include MonitorMixin
7
+
8
+ attr_reader :db_config, :role, :shard
9
+ attr_writer :schema_reflection, :server_version
10
+ attr_accessor :connection_class
11
+
12
+ def schema_reflection
13
+ @schema_reflection ||= SchemaReflection.new(db_config.lazy_schema_cache_path)
14
+ end
15
+
16
+ INSTANCES = ObjectSpace::WeakMap.new
17
+ private_constant :INSTANCES
18
+
19
+ class << self
20
+ def discard_pools!
21
+ INSTANCES.each_key(&:discard_pool!)
22
+ end
23
+
24
+ def disconnect_all!
25
+ INSTANCES.each_key { |c| c.disconnect!(automatic_reconnect: true) }
26
+ end
27
+ end
28
+
29
+ def initialize(connection_class, db_config, role, shard)
30
+ super()
31
+ @server_version = nil
32
+ @connection_class = connection_class
33
+ @db_config = db_config
34
+ @role = role
35
+ @shard = shard
36
+ @pool = nil
37
+ INSTANCES[self] = self
38
+ end
39
+
40
+ def server_version(connection)
41
+ @server_version || synchronize { @server_version ||= connection.get_database_version }
42
+ end
43
+
44
+ def connection_name
45
+ if connection_class.primary_class?
46
+ "ActiveRecord::Base"
47
+ else
48
+ connection_class.name
49
+ end
50
+ end
51
+
52
+ def disconnect!(automatic_reconnect: false)
53
+ return unless @pool
54
+
55
+ synchronize do
56
+ return unless @pool
57
+
58
+ @pool.automatic_reconnect = automatic_reconnect
59
+ @pool.disconnect!
60
+ end
61
+
62
+ nil
63
+ end
64
+
65
+ def pool
66
+ @pool || synchronize { @pool ||= ConnectionAdapters::ConnectionPool.new(self) }
67
+ end
68
+
69
+ def discard_pool!
70
+ return unless @pool
71
+
72
+ synchronize do
73
+ return unless @pool
74
+
75
+ @pool.discard!
76
+ @pool = nil
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ ActiveSupport::ForkTracker.after_fork { ActiveRecord::ConnectionAdapters::PoolConfig.discard_pools! }