activerecord 5.2.8 → 7.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (364) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1393 -587
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +10 -9
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +122 -47
  10. data/lib/active_record/associations/association_scope.rb +24 -24
  11. data/lib/active_record/associations/belongs_to_association.rb +67 -49
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
  13. data/lib/active_record/associations/builder/association.rb +52 -23
  14. data/lib/active_record/associations/builder/belongs_to.rb +44 -61
  15. data/lib/active_record/associations/builder/collection_association.rb +17 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +10 -3
  18. data/lib/active_record/associations/builder/has_one.rb +35 -3
  19. data/lib/active_record/associations/builder/singular_association.rb +5 -3
  20. data/lib/active_record/associations/collection_association.rb +59 -50
  21. data/lib/active_record/associations/collection_proxy.rb +32 -23
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +27 -14
  25. data/lib/active_record/associations/has_many_through_association.rb +26 -19
  26. data/lib/active_record/associations/has_one_association.rb +52 -37
  27. data/lib/active_record/associations/has_one_through_association.rb +6 -6
  28. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +97 -62
  31. data/lib/active_record/associations/preloader/association.rb +220 -60
  32. data/lib/active_record/associations/preloader/batch.rb +48 -0
  33. data/lib/active_record/associations/preloader/branch.rb +147 -0
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -40
  35. data/lib/active_record/associations/preloader.rb +44 -105
  36. data/lib/active_record/associations/singular_association.rb +9 -17
  37. data/lib/active_record/associations/through_association.rb +4 -4
  38. data/lib/active_record/associations.rb +207 -66
  39. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  40. data/lib/active_record/attribute_assignment.rb +17 -19
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
  42. data/lib/active_record/attribute_methods/dirty.rb +141 -47
  43. data/lib/active_record/attribute_methods/primary_key.rb +22 -27
  44. data/lib/active_record/attribute_methods/query.rb +6 -10
  45. data/lib/active_record/attribute_methods/read.rb +15 -55
  46. data/lib/active_record/attribute_methods/serialization.rb +77 -18
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
  48. data/lib/active_record/attribute_methods/write.rb +18 -37
  49. data/lib/active_record/attribute_methods.rb +90 -153
  50. data/lib/active_record/attributes.rb +38 -12
  51. data/lib/active_record/autosave_association.rb +50 -50
  52. data/lib/active_record/base.rb +23 -18
  53. data/lib/active_record/callbacks.rb +159 -44
  54. data/lib/active_record/coders/yaml_column.rb +12 -3
  55. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
  63. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
  71. data/lib/active_record/connection_adapters/column.rb +33 -11
  72. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  73. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  74. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  75. data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
  76. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  77. data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
  78. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  80. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
  81. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
  82. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  83. data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
  84. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  85. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
  95. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
  116. data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
  122. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
  123. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  124. data/lib/active_record/connection_adapters.rb +53 -0
  125. data/lib/active_record/connection_handling.rb +292 -38
  126. data/lib/active_record/core.rb +385 -158
  127. data/lib/active_record/counter_cache.rb +8 -30
  128. data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
  129. data/lib/active_record/database_configurations/database_config.rb +83 -0
  130. data/lib/active_record/database_configurations/hash_config.rb +154 -0
  131. data/lib/active_record/database_configurations/url_config.rb +53 -0
  132. data/lib/active_record/database_configurations.rb +256 -0
  133. data/lib/active_record/delegated_type.rb +250 -0
  134. data/lib/active_record/destroy_association_async_job.rb +36 -0
  135. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  136. data/lib/active_record/dynamic_matchers.rb +4 -5
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +44 -0
  140. data/lib/active_record/encryption/configurable.rb +61 -0
  141. data/lib/active_record/encryption/context.rb +35 -0
  142. data/lib/active_record/encryption/contexts.rb +72 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +155 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +42 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_serializer.rb +90 -0
  159. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  160. data/lib/active_record/encryption/properties.rb +76 -0
  161. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  162. data/lib/active_record/encryption/scheme.rb +99 -0
  163. data/lib/active_record/encryption.rb +55 -0
  164. data/lib/active_record/enum.rb +130 -51
  165. data/lib/active_record/errors.rb +129 -23
  166. data/lib/active_record/explain.rb +10 -6
  167. data/lib/active_record/explain_registry.rb +11 -6
  168. data/lib/active_record/explain_subscriber.rb +1 -1
  169. data/lib/active_record/fixture_set/file.rb +22 -15
  170. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  171. data/lib/active_record/fixture_set/render_context.rb +17 -0
  172. data/lib/active_record/fixture_set/table_row.rb +187 -0
  173. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  174. data/lib/active_record/fixtures.rb +206 -490
  175. data/lib/active_record/future_result.rb +139 -0
  176. data/lib/active_record/gem_version.rb +3 -3
  177. data/lib/active_record/inheritance.rb +104 -37
  178. data/lib/active_record/insert_all.rb +278 -0
  179. data/lib/active_record/integration.rb +69 -18
  180. data/lib/active_record/internal_metadata.rb +24 -9
  181. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  182. data/lib/active_record/locking/optimistic.rb +41 -26
  183. data/lib/active_record/locking/pessimistic.rb +18 -8
  184. data/lib/active_record/log_subscriber.rb +46 -35
  185. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  186. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  187. data/lib/active_record/middleware/database_selector.rb +82 -0
  188. data/lib/active_record/middleware/shard_selector.rb +60 -0
  189. data/lib/active_record/migration/command_recorder.rb +96 -44
  190. data/lib/active_record/migration/compatibility.rb +246 -64
  191. data/lib/active_record/migration/join_table.rb +1 -2
  192. data/lib/active_record/migration.rb +266 -187
  193. data/lib/active_record/model_schema.rb +165 -52
  194. data/lib/active_record/nested_attributes.rb +17 -19
  195. data/lib/active_record/no_touching.rb +11 -4
  196. data/lib/active_record/null_relation.rb +2 -7
  197. data/lib/active_record/persistence.rb +467 -92
  198. data/lib/active_record/query_cache.rb +21 -4
  199. data/lib/active_record/query_logs.rb +138 -0
  200. data/lib/active_record/querying.rb +51 -24
  201. data/lib/active_record/railtie.rb +224 -57
  202. data/lib/active_record/railties/console_sandbox.rb +2 -4
  203. data/lib/active_record/railties/controller_runtime.rb +31 -36
  204. data/lib/active_record/railties/databases.rake +369 -101
  205. data/lib/active_record/readonly_attributes.rb +15 -0
  206. data/lib/active_record/reflection.rb +170 -137
  207. data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
  208. data/lib/active_record/relation/batches.rb +46 -37
  209. data/lib/active_record/relation/calculations.rb +168 -96
  210. data/lib/active_record/relation/delegation.rb +37 -52
  211. data/lib/active_record/relation/finder_methods.rb +79 -58
  212. data/lib/active_record/relation/from_clause.rb +5 -1
  213. data/lib/active_record/relation/merger.rb +50 -51
  214. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  215. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  216. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  217. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  218. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  219. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  220. data/lib/active_record/relation/predicate_builder.rb +58 -46
  221. data/lib/active_record/relation/query_attribute.rb +9 -10
  222. data/lib/active_record/relation/query_methods.rb +685 -208
  223. data/lib/active_record/relation/record_fetch_warning.rb +9 -11
  224. data/lib/active_record/relation/spawn_methods.rb +10 -10
  225. data/lib/active_record/relation/where_clause.rb +108 -64
  226. data/lib/active_record/relation.rb +515 -151
  227. data/lib/active_record/result.rb +78 -42
  228. data/lib/active_record/runtime_registry.rb +9 -13
  229. data/lib/active_record/sanitization.rb +29 -44
  230. data/lib/active_record/schema.rb +37 -31
  231. data/lib/active_record/schema_dumper.rb +74 -23
  232. data/lib/active_record/schema_migration.rb +7 -9
  233. data/lib/active_record/scoping/default.rb +62 -17
  234. data/lib/active_record/scoping/named.rb +17 -32
  235. data/lib/active_record/scoping.rb +70 -41
  236. data/lib/active_record/secure_token.rb +16 -8
  237. data/lib/active_record/serialization.rb +6 -4
  238. data/lib/active_record/signed_id.rb +116 -0
  239. data/lib/active_record/statement_cache.rb +49 -6
  240. data/lib/active_record/store.rb +88 -9
  241. data/lib/active_record/suppressor.rb +13 -17
  242. data/lib/active_record/table_metadata.rb +42 -43
  243. data/lib/active_record/tasks/database_tasks.rb +352 -94
  244. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  245. data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
  246. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  247. data/lib/active_record/test_databases.rb +24 -0
  248. data/lib/active_record/test_fixtures.rb +287 -0
  249. data/lib/active_record/timestamp.rb +44 -34
  250. data/lib/active_record/touch_later.rb +23 -22
  251. data/lib/active_record/transactions.rb +67 -128
  252. data/lib/active_record/translation.rb +3 -3
  253. data/lib/active_record/type/adapter_specific_registry.rb +34 -19
  254. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  255. data/lib/active_record/type/internal/timezone.rb +2 -2
  256. data/lib/active_record/type/serialized.rb +7 -4
  257. data/lib/active_record/type/time.rb +10 -0
  258. data/lib/active_record/type/type_map.rb +17 -21
  259. data/lib/active_record/type/unsigned_integer.rb +0 -1
  260. data/lib/active_record/type.rb +9 -5
  261. data/lib/active_record/type_caster/connection.rb +15 -15
  262. data/lib/active_record/type_caster/map.rb +8 -8
  263. data/lib/active_record/validations/associated.rb +2 -3
  264. data/lib/active_record/validations/numericality.rb +35 -0
  265. data/lib/active_record/validations/uniqueness.rb +39 -31
  266. data/lib/active_record/validations.rb +4 -3
  267. data/lib/active_record.rb +209 -32
  268. data/lib/arel/alias_predication.rb +9 -0
  269. data/lib/arel/attributes/attribute.rb +33 -0
  270. data/lib/arel/collectors/bind.rb +29 -0
  271. data/lib/arel/collectors/composite.rb +39 -0
  272. data/lib/arel/collectors/plain_string.rb +20 -0
  273. data/lib/arel/collectors/sql_string.rb +27 -0
  274. data/lib/arel/collectors/substitute_binds.rb +35 -0
  275. data/lib/arel/crud.rb +48 -0
  276. data/lib/arel/delete_manager.rb +32 -0
  277. data/lib/arel/errors.rb +9 -0
  278. data/lib/arel/expressions.rb +29 -0
  279. data/lib/arel/factory_methods.rb +49 -0
  280. data/lib/arel/filter_predications.rb +9 -0
  281. data/lib/arel/insert_manager.rb +48 -0
  282. data/lib/arel/math.rb +45 -0
  283. data/lib/arel/nodes/and.rb +32 -0
  284. data/lib/arel/nodes/ascending.rb +23 -0
  285. data/lib/arel/nodes/binary.rb +126 -0
  286. data/lib/arel/nodes/bind_param.rb +44 -0
  287. data/lib/arel/nodes/case.rb +55 -0
  288. data/lib/arel/nodes/casted.rb +62 -0
  289. data/lib/arel/nodes/comment.rb +29 -0
  290. data/lib/arel/nodes/count.rb +12 -0
  291. data/lib/arel/nodes/delete_statement.rb +44 -0
  292. data/lib/arel/nodes/descending.rb +23 -0
  293. data/lib/arel/nodes/equality.rb +15 -0
  294. data/lib/arel/nodes/extract.rb +24 -0
  295. data/lib/arel/nodes/false.rb +16 -0
  296. data/lib/arel/nodes/filter.rb +10 -0
  297. data/lib/arel/nodes/full_outer_join.rb +8 -0
  298. data/lib/arel/nodes/function.rb +45 -0
  299. data/lib/arel/nodes/grouping.rb +11 -0
  300. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  301. data/lib/arel/nodes/in.rb +15 -0
  302. data/lib/arel/nodes/infix_operation.rb +92 -0
  303. data/lib/arel/nodes/inner_join.rb +8 -0
  304. data/lib/arel/nodes/insert_statement.rb +37 -0
  305. data/lib/arel/nodes/join_source.rb +20 -0
  306. data/lib/arel/nodes/matches.rb +18 -0
  307. data/lib/arel/nodes/named_function.rb +23 -0
  308. data/lib/arel/nodes/node.rb +51 -0
  309. data/lib/arel/nodes/node_expression.rb +13 -0
  310. data/lib/arel/nodes/ordering.rb +27 -0
  311. data/lib/arel/nodes/outer_join.rb +8 -0
  312. data/lib/arel/nodes/over.rb +15 -0
  313. data/lib/arel/nodes/regexp.rb +16 -0
  314. data/lib/arel/nodes/right_outer_join.rb +8 -0
  315. data/lib/arel/nodes/select_core.rb +67 -0
  316. data/lib/arel/nodes/select_statement.rb +41 -0
  317. data/lib/arel/nodes/sql_literal.rb +19 -0
  318. data/lib/arel/nodes/string_join.rb +11 -0
  319. data/lib/arel/nodes/table_alias.rb +31 -0
  320. data/lib/arel/nodes/terminal.rb +16 -0
  321. data/lib/arel/nodes/true.rb +16 -0
  322. data/lib/arel/nodes/unary.rb +44 -0
  323. data/lib/arel/nodes/unary_operation.rb +20 -0
  324. data/lib/arel/nodes/unqualified_column.rb +22 -0
  325. data/lib/arel/nodes/update_statement.rb +46 -0
  326. data/lib/arel/nodes/values_list.rb +9 -0
  327. data/lib/arel/nodes/window.rb +126 -0
  328. data/lib/arel/nodes/with.rb +11 -0
  329. data/lib/arel/nodes.rb +71 -0
  330. data/lib/arel/order_predications.rb +13 -0
  331. data/lib/arel/predications.rb +258 -0
  332. data/lib/arel/select_manager.rb +276 -0
  333. data/lib/arel/table.rb +117 -0
  334. data/lib/arel/tree_manager.rb +60 -0
  335. data/lib/arel/update_manager.rb +48 -0
  336. data/lib/arel/visitors/dot.rb +298 -0
  337. data/lib/arel/visitors/mysql.rb +99 -0
  338. data/lib/arel/visitors/postgresql.rb +110 -0
  339. data/lib/arel/visitors/sqlite.rb +38 -0
  340. data/lib/arel/visitors/to_sql.rb +955 -0
  341. data/lib/arel/visitors/visitor.rb +45 -0
  342. data/lib/arel/visitors.rb +13 -0
  343. data/lib/arel/window_predications.rb +9 -0
  344. data/lib/arel.rb +55 -0
  345. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  346. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  347. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  348. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  349. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  350. data/lib/rails/generators/active_record/migration.rb +19 -2
  351. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  352. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  353. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  354. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  355. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  356. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  357. metadata +162 -32
  358. data/lib/active_record/attribute_decorators.rb +0 -90
  359. data/lib/active_record/collection_cache_key.rb +0 -53
  360. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  361. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  362. data/lib/active_record/define_callbacks.rb +0 -22
  363. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  364. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -4,54 +4,70 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module MySQL
6
6
  module ColumnMethods
7
- def blob(*args, **options)
8
- args.each { |name| column(name, :blob, options) }
9
- end
7
+ extend ActiveSupport::Concern
10
8
 
11
- def tinyblob(*args, **options)
12
- args.each { |name| column(name, :tinyblob, options) }
13
- end
9
+ ##
10
+ # :method: blob
11
+ # :call-seq: blob(*names, **options)
14
12
 
15
- def mediumblob(*args, **options)
16
- args.each { |name| column(name, :mediumblob, options) }
17
- end
13
+ ##
14
+ # :method: tinyblob
15
+ # :call-seq: tinyblob(*names, **options)
18
16
 
19
- def longblob(*args, **options)
20
- args.each { |name| column(name, :longblob, options) }
21
- end
17
+ ##
18
+ # :method: mediumblob
19
+ # :call-seq: mediumblob(*names, **options)
22
20
 
23
- def tinytext(*args, **options)
24
- args.each { |name| column(name, :tinytext, options) }
25
- end
21
+ ##
22
+ # :method: longblob
23
+ # :call-seq: longblob(*names, **options)
26
24
 
27
- def mediumtext(*args, **options)
28
- args.each { |name| column(name, :mediumtext, options) }
29
- end
25
+ ##
26
+ # :method: tinytext
27
+ # :call-seq: tinytext(*names, **options)
30
28
 
31
- def longtext(*args, **options)
32
- args.each { |name| column(name, :longtext, options) }
33
- end
29
+ ##
30
+ # :method: mediumtext
31
+ # :call-seq: mediumtext(*names, **options)
34
32
 
35
- def unsigned_integer(*args, **options)
36
- args.each { |name| column(name, :unsigned_integer, options) }
37
- end
33
+ ##
34
+ # :method: longtext
35
+ # :call-seq: longtext(*names, **options)
38
36
 
39
- def unsigned_bigint(*args, **options)
40
- args.each { |name| column(name, :unsigned_bigint, options) }
41
- end
37
+ ##
38
+ # :method: unsigned_integer
39
+ # :call-seq: unsigned_integer(*names, **options)
42
40
 
43
- def unsigned_float(*args, **options)
44
- args.each { |name| column(name, :unsigned_float, options) }
45
- end
41
+ ##
42
+ # :method: unsigned_bigint
43
+ # :call-seq: unsigned_bigint(*names, **options)
44
+
45
+ ##
46
+ # :method: unsigned_float
47
+ # :call-seq: unsigned_float(*names, **options)
48
+
49
+ ##
50
+ # :method: unsigned_decimal
51
+ # :call-seq: unsigned_decimal(*names, **options)
46
52
 
47
- def unsigned_decimal(*args, **options)
48
- args.each { |name| column(name, :unsigned_decimal, options) }
53
+ included do
54
+ define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
55
+ :tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint,
56
+ :unsigned_float, :unsigned_decimal
49
57
  end
50
58
  end
51
59
 
52
60
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
53
61
  include ColumnMethods
54
62
 
63
+ attr_reader :charset, :collation
64
+
65
+ def initialize(conn, name, charset: nil, collation: nil, **)
66
+ super
67
+ @charset = charset
68
+ @collation = collation
69
+ end
70
+
55
71
  def new_column_definition(name, type, **options) # :nodoc:
56
72
  case type
57
73
  when :virtual
@@ -10,6 +10,10 @@ module ActiveRecord
10
10
  spec[:unsigned] = "true" if column.unsigned?
11
11
  spec[:auto_increment] = "true" if column.auto_increment?
12
12
 
13
+ if /\A(?<size>tiny|medium|long)(?:text|blob)/ =~ column.sql_type
14
+ spec = { size: size.to_sym.inspect }.merge!(spec)
15
+ end
16
+
13
17
  if @connection.supports_virtual_columns? && column.virtual?
14
18
  spec[:as] = extract_expression_for_virtual_column(column)
15
19
  spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
@@ -37,19 +41,29 @@ module ActiveRecord
37
41
  case column.sql_type
38
42
  when /\Atimestamp\b/
39
43
  :timestamp
40
- when "tinyblob"
41
- :blob
44
+ when /\A(?:enum|set)\b/
45
+ column.sql_type
42
46
  else
43
47
  super
44
48
  end
45
49
  end
46
50
 
51
+ def schema_limit(column)
52
+ super unless /\A(?:tiny|medium|long)?(?:text|blob)\b/.match?(column.sql_type)
53
+ end
54
+
47
55
  def schema_precision(column)
48
- super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
56
+ if /\Atime(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
57
+ nil
58
+ elsif column.type == :datetime
59
+ column.precision == 0 ? "nil" : super
60
+ else
61
+ super
62
+ end
49
63
  end
50
64
 
51
65
  def schema_collation(column)
52
- if column.collation && table_name = column.table_name
66
+ if column.collation
53
67
  @table_collation_cache ||= {}
54
68
  @table_collation_cache[table_name] ||=
55
69
  @connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
@@ -58,20 +72,23 @@ module ActiveRecord
58
72
  end
59
73
 
60
74
  def extract_expression_for_virtual_column(column)
61
- if @connection.mariadb? && @connection.version < "10.2.5"
62
- create_table_info = @connection.send(:create_table_info, column.table_name)
75
+ if @connection.mariadb? && @connection.database_version < "10.2.5"
76
+ create_table_info = @connection.send(:create_table_info, table_name)
63
77
  column_name = @connection.quote_column_name(column.name)
64
78
  if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
65
79
  $~[:expression].inspect
66
80
  end
67
81
  else
68
- scope = @connection.send(:quoted_scope, column.table_name)
82
+ scope = @connection.send(:quoted_scope, table_name)
69
83
  column_name = @connection.quote(column.name)
70
84
  sql = "SELECT generation_expression FROM information_schema.columns" \
71
85
  " WHERE table_schema = #{scope[:schema]}" \
72
86
  " AND table_name = #{scope[:name]}" \
73
87
  " AND column_name = #{column_name}"
74
- @connection.query_value(sql, "SCHEMA").inspect
88
+ # Calling .inspect leads into issues with the query result
89
+ # which already returns escaped quotes.
90
+ # We remove the escape sequence from the result in order to deal with double escaping issues.
91
+ @connection.query_value(sql, "SCHEMA").gsub("\\'", "'").inspect
75
92
  end
76
93
  end
77
94
  end
@@ -35,25 +35,55 @@ module ActiveRecord
35
35
  ]
36
36
  end
37
37
 
38
- indexes.last[-2] << row[:Column_name]
39
- indexes.last[-1][:lengths].merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part]
40
- indexes.last[-1][:orders].merge!(row[:Column_name] => :desc) if row[:Collation] == "D"
38
+ if row[:Expression]
39
+ expression = row[:Expression]
40
+ expression = +"(#{expression})" unless expression.start_with?("(")
41
+ indexes.last[-2] << expression
42
+ indexes.last[-1][:expressions] ||= {}
43
+ indexes.last[-1][:expressions][expression] = expression
44
+ indexes.last[-1][:orders][expression] = :desc if row[:Collation] == "D"
45
+ else
46
+ indexes.last[-2] << row[:Column_name]
47
+ indexes.last[-1][:lengths][row[:Column_name]] = row[:Sub_part].to_i if row[:Sub_part]
48
+ indexes.last[-1][:orders][row[:Column_name]] = :desc if row[:Collation] == "D"
49
+ end
41
50
  end
42
51
  end
43
52
 
44
- indexes.map { |index| IndexDefinition.new(*index) }
53
+ indexes.map do |index|
54
+ options = index.pop
55
+
56
+ if expressions = options.delete(:expressions)
57
+ orders = options.delete(:orders)
58
+ lengths = options.delete(:lengths)
59
+
60
+ columns = index[-1].map { |name|
61
+ [ name.to_sym, expressions[name] || +quote_column_name(name) ]
62
+ }.to_h
63
+
64
+ index[-1] = add_options_for_index_columns(
65
+ columns, order: orders, length: lengths
66
+ ).values.join(", ")
67
+ end
68
+
69
+ IndexDefinition.new(*index, **options)
70
+ end
45
71
  end
46
72
 
47
- def remove_column(table_name, column_name, type = nil, options = {})
73
+ def remove_column(table_name, column_name, type = nil, **options)
48
74
  if foreign_key_exists?(table_name, column: column_name)
49
75
  remove_foreign_key(table_name, column: column_name)
50
76
  end
51
77
  super
52
78
  end
53
79
 
80
+ def create_table(table_name, options: default_row_format, **)
81
+ super
82
+ end
83
+
54
84
  def internal_string_options_for_primary_key
55
85
  super.tap do |options|
56
- if CHARSETS_OF_4BYTES_MAXLEN.include?(charset) && (mariadb? || version < "8.0.0")
86
+ if !row_format_dynamic_by_default? && CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
57
87
  options[:collation] = collation.sub(/\A[^_]+/, "utf8")
58
88
  end
59
89
  end
@@ -67,23 +97,80 @@ module ActiveRecord
67
97
  MySQL::SchemaDumper.create(self, options)
68
98
  end
69
99
 
100
+ # Maps logical Rails types to MySQL-specific data types.
101
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, size: limit_to_size(limit, type), unsigned: nil, **)
102
+ sql =
103
+ case type.to_s
104
+ when "integer"
105
+ integer_to_sql(limit)
106
+ when "text"
107
+ type_with_size_to_sql("text", size)
108
+ when "blob"
109
+ type_with_size_to_sql("blob", size)
110
+ when "binary"
111
+ if (0..0xfff) === limit
112
+ "varbinary(#{limit})"
113
+ else
114
+ type_with_size_to_sql("blob", size)
115
+ end
116
+ else
117
+ super
118
+ end
119
+
120
+ sql = "#{sql} unsigned" if unsigned && type != :primary_key
121
+ sql
122
+ end
123
+
124
+ def table_alias_length
125
+ 256 # https://dev.mysql.com/doc/refman/en/identifiers.html
126
+ end
127
+
70
128
  private
71
129
  CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
72
130
 
131
+ def row_format_dynamic_by_default?
132
+ if mariadb?
133
+ database_version >= "10.2.2"
134
+ else
135
+ database_version >= "5.7.9"
136
+ end
137
+ end
138
+
139
+ def default_row_format
140
+ return if row_format_dynamic_by_default?
141
+
142
+ unless defined?(@default_row_format)
143
+ if query_value("SELECT @@innodb_file_per_table = 1 AND @@innodb_file_format = 'Barracuda'") == 1
144
+ @default_row_format = "ROW_FORMAT=DYNAMIC"
145
+ else
146
+ @default_row_format = nil
147
+ end
148
+ end
149
+
150
+ @default_row_format
151
+ end
152
+
73
153
  def schema_creation
74
154
  MySQL::SchemaCreation.new(self)
75
155
  end
76
156
 
77
- def create_table_definition(*args)
78
- MySQL::TableDefinition.new(*args)
157
+ def create_table_definition(name, **options)
158
+ MySQL::TableDefinition.new(self, name, **options)
79
159
  end
80
160
 
81
161
  def new_column_from_field(table_name, field)
82
162
  type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
83
- if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
84
- default, default_function = nil, field[:Default]
85
- else
86
- default, default_function = field[:Default], nil
163
+ default, default_function = field[:Default], nil
164
+
165
+ if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
166
+ default = "#{default} ON UPDATE #{default}" if /on update CURRENT_TIMESTAMP/i.match?(field[:Extra])
167
+ default, default_function = nil, default
168
+ elsif type_metadata.extra == "DEFAULT_GENERATED"
169
+ default = +"(#{default})" unless default.start_with?("(")
170
+ default, default_function = nil, default
171
+ elsif type_metadata.type == :text && default
172
+ # strip and unescape quotes
173
+ default = default[1...-1].gsub("\\'", "'")
87
174
  end
88
175
 
89
176
  MySQL::Column.new(
@@ -91,9 +178,8 @@ module ActiveRecord
91
178
  default,
92
179
  type_metadata,
93
180
  field[:Null] == "YES",
94
- table_name,
95
181
  default_function,
96
- field[:Collation],
182
+ collation: field[:Collation],
97
183
  comment: field[:Comment].presence
98
184
  )
99
185
  end
@@ -114,17 +200,21 @@ module ActiveRecord
114
200
  end
115
201
 
116
202
  def add_options_for_index_columns(quoted_columns, **options)
117
- quoted_columns = add_index_length(quoted_columns, options)
203
+ quoted_columns = add_index_length(quoted_columns, **options)
118
204
  super
119
205
  end
120
206
 
121
207
  def data_source_sql(name = nil, type: nil)
122
208
  scope = quoted_scope(name, type: type)
123
209
 
124
- sql = "SELECT table_name FROM information_schema.tables".dup
125
- sql << " WHERE table_schema = #{scope[:schema]}"
126
- sql << " AND table_name = #{scope[:name]}" if scope[:name]
127
- sql << " AND table_type = #{scope[:type]}" if scope[:type]
210
+ sql = +"SELECT table_name FROM (SELECT table_name, table_type FROM information_schema.tables "
211
+ sql << " WHERE table_schema = #{scope[:schema]}) _subquery"
212
+ if scope[:type] || scope[:name]
213
+ conditions = []
214
+ conditions << "_subquery.table_type = #{scope[:type]}" if scope[:type]
215
+ conditions << "_subquery.table_name = #{scope[:name]}" if scope[:name]
216
+ sql << " WHERE #{conditions.join(" AND ")}"
217
+ end
128
218
  sql
129
219
  end
130
220
 
@@ -142,6 +232,40 @@ module ActiveRecord
142
232
  schema, name = nil, schema unless name
143
233
  [schema, name]
144
234
  end
235
+
236
+ def type_with_size_to_sql(type, size)
237
+ case size&.to_s
238
+ when nil, "tiny", "medium", "long"
239
+ "#{size}#{type}"
240
+ else
241
+ raise ArgumentError,
242
+ "#{size.inspect} is invalid :size value. Only :tiny, :medium, and :long are allowed."
243
+ end
244
+ end
245
+
246
+ def limit_to_size(limit, type)
247
+ case type.to_s
248
+ when "text", "blob", "binary"
249
+ case limit
250
+ when 0..0xff; "tiny"
251
+ when nil, 0x100..0xffff; nil
252
+ when 0x10000..0xffffff; "medium"
253
+ when 0x1000000..0xffffffff; "long"
254
+ else raise ArgumentError, "No #{type} type has byte size #{limit}"
255
+ end
256
+ end
257
+ end
258
+
259
+ def integer_to_sql(limit)
260
+ case limit
261
+ when 1; "tinyint"
262
+ when 2; "smallint"
263
+ when 3; "mediumint"
264
+ when nil, 4; "int"
265
+ when 5..8; "bigint"
266
+ else raise ArgumentError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead."
267
+ end
268
+ end
145
269
  end
146
270
  end
147
271
  end
@@ -6,28 +6,33 @@ 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
- @type_metadata = type_metadata
14
15
  @extra = extra
15
16
  end
16
17
 
17
18
  def ==(other)
18
- other.is_a?(MySQL::TypeMetadata) &&
19
- attributes_for_hash == other.attributes_for_hash
19
+ other.is_a?(TypeMetadata) &&
20
+ __getobj__ == other.__getobj__ &&
21
+ extra == other.extra
20
22
  end
21
23
  alias eql? ==
22
24
 
23
25
  def hash
24
- attributes_for_hash.hash
26
+ TypeMetadata.hash ^
27
+ __getobj__.hash ^
28
+ extra.hash
25
29
  end
26
30
 
27
- protected
28
-
29
- def attributes_for_hash
30
- [self.class, @type_metadata, extra]
31
+ private
32
+ def deduplicated
33
+ __setobj__(__getobj__.deduplicate)
34
+ @extra = -extra if extra
35
+ super
31
36
  end
32
37
  end
33
38
  end
@@ -3,7 +3,7 @@
3
3
  require "active_record/connection_adapters/abstract_mysql_adapter"
4
4
  require "active_record/connection_adapters/mysql/database_statements"
5
5
 
6
- gem "mysql2", ">= 0.4.4", "< 0.6.0"
6
+ gem "mysql2", "~> 0.5"
7
7
  require "mysql2"
8
8
 
9
9
  module ActiveRecord
@@ -14,36 +14,61 @@ module ActiveRecord
14
14
  config[:flags] ||= 0
15
15
 
16
16
  if config[:flags].kind_of? Array
17
- config[:flags].push "FOUND_ROWS".freeze
17
+ config[:flags].push "FOUND_ROWS"
18
18
  else
19
19
  config[:flags] |= Mysql2::Client::FOUND_ROWS
20
20
  end
21
21
 
22
- client = Mysql2::Client.new(config)
23
- ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
24
- rescue Mysql2::Error => error
25
- if error.message.include?("Unknown database")
26
- raise ActiveRecord::NoDatabaseError
27
- else
28
- raise
29
- end
22
+ ConnectionAdapters::Mysql2Adapter.new(
23
+ ConnectionAdapters::Mysql2Adapter.new_client(config),
24
+ logger,
25
+ nil,
26
+ config,
27
+ )
30
28
  end
31
29
  end
32
30
 
33
31
  module ConnectionAdapters
34
32
  class Mysql2Adapter < AbstractMysqlAdapter
35
- ADAPTER_NAME = "Mysql2".freeze
33
+ ER_BAD_DB_ERROR = 1049
34
+ ER_ACCESS_DENIED_ERROR = 1045
35
+ ER_CONN_HOST_ERROR = 2003
36
+ ER_UNKNOWN_HOST_ERROR = 2005
37
+
38
+ ADAPTER_NAME = "Mysql2"
36
39
 
37
40
  include MySQL::DatabaseStatements
38
41
 
42
+ class << self
43
+ def new_client(config)
44
+ Mysql2::Client.new(config)
45
+ rescue Mysql2::Error => error
46
+ if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
47
+ raise ActiveRecord::NoDatabaseError.db_error(config[:database])
48
+ elsif error.error_number == ConnectionAdapters::Mysql2Adapter::ER_ACCESS_DENIED_ERROR
49
+ raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
50
+ elsif [ConnectionAdapters::Mysql2Adapter::ER_CONN_HOST_ERROR, ConnectionAdapters::Mysql2Adapter::ER_UNKNOWN_HOST_ERROR].include?(error.error_number)
51
+ raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
52
+ else
53
+ raise ActiveRecord::ConnectionNotEstablished, error.message
54
+ end
55
+ end
56
+ end
57
+
39
58
  def initialize(connection, logger, connection_options, config)
40
- super
41
- @prepared_statements = false unless config.key?(:prepared_statements)
59
+ superclass_config = config.reverse_merge(prepared_statements: false)
60
+ super(connection, logger, connection_options, superclass_config)
42
61
  configure_connection
43
62
  end
44
63
 
64
+ def self.database_exists?(config)
65
+ !!ActiveRecord::Base.mysql2_connection(config)
66
+ rescue ActiveRecord::NoDatabaseError
67
+ false
68
+ end
69
+
45
70
  def supports_json?
46
- !mariadb? && version >= "5.7.8"
71
+ !mariadb? && database_version >= "5.7.8"
47
72
  end
48
73
 
49
74
  def supports_comments?
@@ -58,13 +83,15 @@ module ActiveRecord
58
83
  true
59
84
  end
60
85
 
86
+ def supports_lazy_transactions?
87
+ true
88
+ end
89
+
61
90
  # HELPER METHODS ===========================================
62
91
 
63
- def each_hash(result) # :nodoc:
92
+ def each_hash(result, &block) # :nodoc:
64
93
  if block_given?
65
- result.each(as: :hash, symbolize_keys: true) do |row|
66
- yield row
67
- end
94
+ result.each(as: :hash, symbolize_keys: true, &block)
68
95
  else
69
96
  to_enum(:each_hash, result)
70
97
  end
@@ -80,6 +107,8 @@ module ActiveRecord
80
107
 
81
108
  def quote_string(string)
82
109
  @connection.escape(string)
110
+ rescue Mysql2::Error => error
111
+ raise translate_exception(error, message: error.message, sql: "<escape>", binds: [])
83
112
  end
84
113
 
85
114
  #--
@@ -105,24 +134,36 @@ module ActiveRecord
105
134
  end
106
135
 
107
136
  def discard! # :nodoc:
137
+ super
108
138
  @connection.automatic_close = false
109
139
  @connection = nil
110
140
  end
111
141
 
112
142
  private
113
-
114
143
  def connect
115
- @connection = Mysql2::Client.new(@config)
144
+ @connection = self.class.new_client(@config)
116
145
  configure_connection
117
146
  end
118
147
 
119
148
  def configure_connection
120
- @connection.query_options.merge!(as: :array)
149
+ @connection.query_options[:as] = :array
121
150
  super
122
151
  end
123
152
 
124
153
  def full_version
125
- @full_version ||= @connection.server_info[:version]
154
+ schema_cache.database_version.full_version_string
155
+ end
156
+
157
+ def get_full_version
158
+ @connection.server_info[:version]
159
+ end
160
+
161
+ def translate_exception(exception, message:, sql:, binds:)
162
+ if exception.is_a?(Mysql2::Error::TimeoutError) && !exception.error_number
163
+ ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds)
164
+ else
165
+ super
166
+ end
126
167
  end
127
168
  end
128
169
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class PoolConfig # :nodoc:
6
+ include Mutex_m
7
+
8
+ attr_reader :db_config, :connection_class, :role, :shard
9
+ attr_accessor :schema_cache
10
+
11
+ INSTANCES = ObjectSpace::WeakMap.new
12
+ private_constant :INSTANCES
13
+
14
+ class << self
15
+ def discard_pools!
16
+ INSTANCES.each_key(&:discard_pool!)
17
+ end
18
+ end
19
+
20
+ def initialize(connection_class, db_config, role, shard)
21
+ super()
22
+ @connection_class = connection_class
23
+ @db_config = db_config
24
+ @role = role
25
+ @shard = shard
26
+ @pool = nil
27
+ INSTANCES[self] = self
28
+ end
29
+
30
+ def connection_specification_name
31
+ if connection_class.primary_class?
32
+ "ActiveRecord::Base"
33
+ else
34
+ connection_class.name
35
+ end
36
+ end
37
+
38
+ def disconnect!
39
+ ActiveSupport::ForkTracker.check!
40
+
41
+ return unless @pool
42
+
43
+ synchronize do
44
+ return unless @pool
45
+
46
+ @pool.automatic_reconnect = false
47
+ @pool.disconnect!
48
+ end
49
+
50
+ nil
51
+ end
52
+
53
+ def pool
54
+ ActiveSupport::ForkTracker.check!
55
+
56
+ @pool || synchronize { @pool ||= ConnectionAdapters::ConnectionPool.new(self) }
57
+ end
58
+
59
+ def discard_pool!
60
+ return unless @pool
61
+
62
+ synchronize do
63
+ return unless @pool
64
+
65
+ @pool.discard!
66
+ @pool = nil
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ ActiveSupport::ForkTracker.after_fork { ActiveRecord::ConnectionAdapters::PoolConfig.discard_pools! }