activerecord 6.1.6 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (309) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1627 -983
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +439 -305
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -34
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -138
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  95. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  96. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  97. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +394 -74
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +509 -247
  101. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  102. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  105. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  106. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  107. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  108. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  109. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  110. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  111. data/lib/active_record/connection_adapters.rb +9 -6
  112. data/lib/active_record/connection_handling.rb +107 -136
  113. data/lib/active_record/core.rb +202 -223
  114. data/lib/active_record/counter_cache.rb +46 -25
  115. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  116. data/lib/active_record/database_configurations/database_config.rb +21 -12
  117. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  118. data/lib/active_record/database_configurations/url_config.rb +18 -12
  119. data/lib/active_record/database_configurations.rb +95 -59
  120. data/lib/active_record/delegated_type.rb +61 -15
  121. data/lib/active_record/deprecator.rb +7 -0
  122. data/lib/active_record/destroy_association_async_job.rb +3 -1
  123. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  124. data/lib/active_record/dynamic_matchers.rb +1 -1
  125. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  126. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  127. data/lib/active_record/encryption/cipher.rb +53 -0
  128. data/lib/active_record/encryption/config.rb +68 -0
  129. data/lib/active_record/encryption/configurable.rb +60 -0
  130. data/lib/active_record/encryption/context.rb +42 -0
  131. data/lib/active_record/encryption/contexts.rb +76 -0
  132. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  133. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  134. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  135. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  136. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  137. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  138. data/lib/active_record/encryption/encryptor.rb +155 -0
  139. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  140. data/lib/active_record/encryption/errors.rb +15 -0
  141. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  142. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  143. data/lib/active_record/encryption/key.rb +28 -0
  144. data/lib/active_record/encryption/key_generator.rb +53 -0
  145. data/lib/active_record/encryption/key_provider.rb +46 -0
  146. data/lib/active_record/encryption/message.rb +33 -0
  147. data/lib/active_record/encryption/message_serializer.rb +92 -0
  148. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  149. data/lib/active_record/encryption/properties.rb +76 -0
  150. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  151. data/lib/active_record/encryption/scheme.rb +96 -0
  152. data/lib/active_record/encryption.rb +56 -0
  153. data/lib/active_record/enum.rb +154 -63
  154. data/lib/active_record/errors.rb +171 -15
  155. data/lib/active_record/explain.rb +23 -3
  156. data/lib/active_record/explain_registry.rb +11 -6
  157. data/lib/active_record/explain_subscriber.rb +1 -1
  158. data/lib/active_record/fixture_set/file.rb +15 -1
  159. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  160. data/lib/active_record/fixture_set/render_context.rb +2 -0
  161. data/lib/active_record/fixture_set/table_row.rb +70 -14
  162. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  163. data/lib/active_record/fixtures.rb +131 -86
  164. data/lib/active_record/future_result.rb +164 -0
  165. data/lib/active_record/gem_version.rb +3 -3
  166. data/lib/active_record/inheritance.rb +81 -29
  167. data/lib/active_record/insert_all.rb +135 -22
  168. data/lib/active_record/integration.rb +11 -10
  169. data/lib/active_record/internal_metadata.rb +119 -33
  170. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  171. data/lib/active_record/locking/optimistic.rb +36 -21
  172. data/lib/active_record/locking/pessimistic.rb +15 -6
  173. data/lib/active_record/log_subscriber.rb +52 -19
  174. data/lib/active_record/marshalling.rb +56 -0
  175. data/lib/active_record/message_pack.rb +124 -0
  176. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  177. data/lib/active_record/middleware/database_selector.rb +23 -13
  178. data/lib/active_record/middleware/shard_selector.rb +62 -0
  179. data/lib/active_record/migration/command_recorder.rb +112 -14
  180. data/lib/active_record/migration/compatibility.rb +221 -48
  181. data/lib/active_record/migration/default_strategy.rb +23 -0
  182. data/lib/active_record/migration/execution_strategy.rb +19 -0
  183. data/lib/active_record/migration/join_table.rb +1 -1
  184. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  185. data/lib/active_record/migration.rb +358 -171
  186. data/lib/active_record/model_schema.rb +120 -101
  187. data/lib/active_record/nested_attributes.rb +37 -18
  188. data/lib/active_record/no_touching.rb +3 -3
  189. data/lib/active_record/normalization.rb +167 -0
  190. data/lib/active_record/persistence.rb +405 -85
  191. data/lib/active_record/promise.rb +84 -0
  192. data/lib/active_record/query_cache.rb +3 -21
  193. data/lib/active_record/query_logs.rb +174 -0
  194. data/lib/active_record/query_logs_formatter.rb +41 -0
  195. data/lib/active_record/querying.rb +29 -6
  196. data/lib/active_record/railtie.rb +219 -43
  197. data/lib/active_record/railties/controller_runtime.rb +13 -9
  198. data/lib/active_record/railties/databases.rake +188 -252
  199. data/lib/active_record/railties/job_runtime.rb +23 -0
  200. data/lib/active_record/readonly_attributes.rb +41 -3
  201. data/lib/active_record/reflection.rb +241 -80
  202. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  203. data/lib/active_record/relation/batches.rb +192 -63
  204. data/lib/active_record/relation/calculations.rb +219 -90
  205. data/lib/active_record/relation/delegation.rb +27 -13
  206. data/lib/active_record/relation/finder_methods.rb +108 -51
  207. data/lib/active_record/relation/merger.rb +22 -13
  208. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  209. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  210. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  211. data/lib/active_record/relation/predicate_builder.rb +27 -20
  212. data/lib/active_record/relation/query_attribute.rb +30 -12
  213. data/lib/active_record/relation/query_methods.rb +654 -127
  214. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  215. data/lib/active_record/relation/spawn_methods.rb +20 -3
  216. data/lib/active_record/relation/where_clause.rb +10 -19
  217. data/lib/active_record/relation.rb +262 -120
  218. data/lib/active_record/result.rb +37 -11
  219. data/lib/active_record/runtime_registry.rb +18 -13
  220. data/lib/active_record/sanitization.rb +65 -20
  221. data/lib/active_record/schema.rb +36 -22
  222. data/lib/active_record/schema_dumper.rb +73 -24
  223. data/lib/active_record/schema_migration.rb +68 -33
  224. data/lib/active_record/scoping/default.rb +72 -15
  225. data/lib/active_record/scoping/named.rb +5 -13
  226. data/lib/active_record/scoping.rb +65 -34
  227. data/lib/active_record/secure_password.rb +60 -0
  228. data/lib/active_record/secure_token.rb +21 -3
  229. data/lib/active_record/serialization.rb +6 -1
  230. data/lib/active_record/signed_id.rb +10 -8
  231. data/lib/active_record/store.rb +16 -11
  232. data/lib/active_record/suppressor.rb +13 -15
  233. data/lib/active_record/table_metadata.rb +16 -3
  234. data/lib/active_record/tasks/database_tasks.rb +225 -136
  235. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  236. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  237. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  238. data/lib/active_record/test_databases.rb +1 -1
  239. data/lib/active_record/test_fixtures.rb +123 -99
  240. data/lib/active_record/timestamp.rb +29 -18
  241. data/lib/active_record/token_for.rb +113 -0
  242. data/lib/active_record/touch_later.rb +11 -6
  243. data/lib/active_record/transactions.rb +48 -27
  244. data/lib/active_record/translation.rb +3 -3
  245. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  246. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  247. data/lib/active_record/type/internal/timezone.rb +7 -2
  248. data/lib/active_record/type/serialized.rb +9 -5
  249. data/lib/active_record/type/time.rb +4 -0
  250. data/lib/active_record/type/type_map.rb +17 -20
  251. data/lib/active_record/type.rb +1 -2
  252. data/lib/active_record/validations/absence.rb +1 -1
  253. data/lib/active_record/validations/associated.rb +4 -4
  254. data/lib/active_record/validations/numericality.rb +5 -4
  255. data/lib/active_record/validations/presence.rb +5 -28
  256. data/lib/active_record/validations/uniqueness.rb +51 -6
  257. data/lib/active_record/validations.rb +8 -4
  258. data/lib/active_record/version.rb +1 -1
  259. data/lib/active_record.rb +335 -32
  260. data/lib/arel/attributes/attribute.rb +0 -8
  261. data/lib/arel/crud.rb +28 -22
  262. data/lib/arel/delete_manager.rb +18 -4
  263. data/lib/arel/errors.rb +10 -0
  264. data/lib/arel/factory_methods.rb +4 -0
  265. data/lib/arel/filter_predications.rb +9 -0
  266. data/lib/arel/insert_manager.rb +2 -3
  267. data/lib/arel/nodes/and.rb +4 -0
  268. data/lib/arel/nodes/binary.rb +6 -1
  269. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  270. data/lib/arel/nodes/casted.rb +1 -1
  271. data/lib/arel/nodes/cte.rb +36 -0
  272. data/lib/arel/nodes/delete_statement.rb +12 -13
  273. data/lib/arel/nodes/filter.rb +10 -0
  274. data/lib/arel/nodes/fragments.rb +35 -0
  275. data/lib/arel/nodes/function.rb +1 -0
  276. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  277. data/lib/arel/nodes/insert_statement.rb +2 -2
  278. data/lib/arel/nodes/leading_join.rb +8 -0
  279. data/lib/arel/nodes/node.rb +111 -2
  280. data/lib/arel/nodes/select_core.rb +2 -2
  281. data/lib/arel/nodes/select_statement.rb +2 -2
  282. data/lib/arel/nodes/sql_literal.rb +6 -0
  283. data/lib/arel/nodes/table_alias.rb +4 -0
  284. data/lib/arel/nodes/update_statement.rb +8 -3
  285. data/lib/arel/nodes.rb +5 -0
  286. data/lib/arel/predications.rb +13 -3
  287. data/lib/arel/select_manager.rb +10 -4
  288. data/lib/arel/table.rb +9 -6
  289. data/lib/arel/tree_manager.rb +0 -12
  290. data/lib/arel/update_manager.rb +18 -4
  291. data/lib/arel/visitors/dot.rb +80 -90
  292. data/lib/arel/visitors/mysql.rb +16 -3
  293. data/lib/arel/visitors/postgresql.rb +0 -10
  294. data/lib/arel/visitors/to_sql.rb +139 -19
  295. data/lib/arel/visitors/visitor.rb +2 -2
  296. data/lib/arel.rb +18 -3
  297. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  298. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  299. data/lib/rails/generators/active_record/migration.rb +3 -1
  300. data/lib/rails/generators/active_record/model/USAGE +113 -0
  301. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  302. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  303. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  304. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  305. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  306. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  307. metadata +93 -13
  308. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  309. data/lib/active_record/null_relation.rb +0 -67
@@ -3,6 +3,7 @@
3
3
  require "active_record/connection_adapters/abstract_adapter"
4
4
  require "active_record/connection_adapters/statement_pool"
5
5
  require "active_record/connection_adapters/mysql/column"
6
+ require "active_record/connection_adapters/mysql/database_statements"
6
7
  require "active_record/connection_adapters/mysql/explain_pretty_printer"
7
8
  require "active_record/connection_adapters/mysql/quoting"
8
9
  require "active_record/connection_adapters/mysql/schema_creation"
@@ -14,6 +15,7 @@ require "active_record/connection_adapters/mysql/type_metadata"
14
15
  module ActiveRecord
15
16
  module ConnectionAdapters
16
17
  class AbstractMysqlAdapter < AbstractAdapter
18
+ include MySQL::DatabaseStatements
17
19
  include MySQL::Quoting
18
20
  include MySQL::SchemaStatements
19
21
 
@@ -31,6 +33,7 @@ module ActiveRecord
31
33
  string: { name: "varchar", limit: 255 },
32
34
  text: { name: "text" },
33
35
  integer: { name: "int", limit: 4 },
36
+ bigint: { name: "bigint" },
34
37
  float: { name: "float", limit: 24 },
35
38
  decimal: { name: "decimal" },
36
39
  datetime: { name: "datetime" },
@@ -50,11 +53,37 @@ module ActiveRecord
50
53
  end
51
54
  end
52
55
 
53
- def initialize(connection, logger, connection_options, config)
54
- super(connection, logger, config)
56
+ class << self
57
+ def dbconsole(config, options = {})
58
+ mysql_config = config.configuration_hash
59
+
60
+ args = {
61
+ host: "--host",
62
+ port: "--port",
63
+ socket: "--socket",
64
+ username: "--user",
65
+ encoding: "--default-character-set",
66
+ sslca: "--ssl-ca",
67
+ sslcert: "--ssl-cert",
68
+ sslcapath: "--ssl-capath",
69
+ sslcipher: "--ssl-cipher",
70
+ sslkey: "--ssl-key",
71
+ ssl_mode: "--ssl-mode"
72
+ }.filter_map { |opt, arg| "#{arg}=#{mysql_config[opt]}" if mysql_config[opt] }
73
+
74
+ if mysql_config[:password] && options[:include_password]
75
+ args << "--password=#{mysql_config[:password]}"
76
+ elsif mysql_config[:password] && !mysql_config[:password].to_s.empty?
77
+ args << "-p"
78
+ end
79
+
80
+ args << config.database
81
+
82
+ find_cmd_and_exec(["mysql", "mysql5"], *args)
83
+ end
55
84
  end
56
85
 
57
- def get_database_version #:nodoc:
86
+ def get_database_version # :nodoc:
58
87
  full_version_string = get_full_version
59
88
  version_string = version_string(full_version_string)
60
89
  Version.new(version_string, full_version_string)
@@ -80,6 +109,10 @@ module ActiveRecord
80
109
  true
81
110
  end
82
111
 
112
+ def supports_restart_db_transaction?
113
+ true
114
+ end
115
+
83
116
  def supports_explain?
84
117
  true
85
118
  end
@@ -94,7 +127,7 @@ module ActiveRecord
94
127
 
95
128
  def supports_check_constraints?
96
129
  if mariadb?
97
- database_version >= "10.2.1"
130
+ database_version >= "10.3.10" || (database_version < "10.3" && database_version >= "10.2.22")
98
131
  else
99
132
  database_version >= "8.0.16"
100
133
  end
@@ -174,7 +207,7 @@ module ActiveRecord
174
207
 
175
208
  # REFERENTIAL INTEGRITY ====================================
176
209
 
177
- def disable_referential_integrity #:nodoc:
210
+ def disable_referential_integrity # :nodoc:
178
211
  old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
179
212
 
180
213
  begin
@@ -185,54 +218,43 @@ module ActiveRecord
185
218
  end
186
219
  end
187
220
 
188
- # CONNECTION MANAGEMENT ====================================
189
-
190
- def clear_cache! # :nodoc:
191
- reload_type_map
192
- super
193
- end
194
-
195
221
  #--
196
222
  # DATABASE STATEMENTS ======================================
197
223
  #++
198
224
 
199
- # Executes the SQL statement in the context of this connection.
200
- def execute(sql, name = nil)
201
- materialize_transactions
202
- mark_transaction_written_if_write(sql)
203
-
204
- log(sql, name) do
205
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
206
- @connection.query(sql)
207
- end
208
- end
209
- end
210
-
211
225
  # Mysql2Adapter doesn't have to free a result after using it, but we use this method
212
226
  # to write stuff in an abstract way without concerning ourselves about whether it
213
227
  # needs to be explicitly freed or not.
214
- def execute_and_free(sql, name = nil) # :nodoc:
215
- yield execute(sql, name)
228
+ def execute_and_free(sql, name = nil, async: false) # :nodoc:
229
+ sql = transform_query(sql)
230
+ check_if_write_query(sql)
231
+
232
+ mark_transaction_written_if_write(sql)
233
+ yield raw_execute(sql, name, async: async)
216
234
  end
217
235
 
218
- def begin_db_transaction
219
- execute("BEGIN", "TRANSACTION")
236
+ def begin_db_transaction # :nodoc:
237
+ internal_execute("BEGIN", "TRANSACTION", allow_retry: true, materialize_transactions: false)
220
238
  end
221
239
 
222
- def begin_isolated_db_transaction(isolation)
223
- execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
240
+ def begin_isolated_db_transaction(isolation) # :nodoc:
241
+ internal_execute("SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}", "TRANSACTION", allow_retry: true, materialize_transactions: false)
224
242
  begin_db_transaction
225
243
  end
226
244
 
227
- def commit_db_transaction #:nodoc:
228
- execute("COMMIT", "TRANSACTION")
245
+ def commit_db_transaction # :nodoc:
246
+ internal_execute("COMMIT", "TRANSACTION", allow_retry: false, materialize_transactions: true)
247
+ end
248
+
249
+ def exec_rollback_db_transaction # :nodoc:
250
+ internal_execute("ROLLBACK", "TRANSACTION", allow_retry: false, materialize_transactions: true)
229
251
  end
230
252
 
231
- def exec_rollback_db_transaction #:nodoc:
232
- execute("ROLLBACK", "TRANSACTION")
253
+ def exec_restart_db_transaction # :nodoc:
254
+ internal_execute("ROLLBACK AND CHAIN", "TRANSACTION", allow_retry: false, materialize_transactions: true)
233
255
  end
234
256
 
235
- def empty_insert_statement_value(primary_key = nil)
257
+ def empty_insert_statement_value(primary_key = nil) # :nodoc:
236
258
  "VALUES ()"
237
259
  end
238
260
 
@@ -270,7 +292,7 @@ module ActiveRecord
270
292
  #
271
293
  # Example:
272
294
  # drop_database('sebastian_development')
273
- def drop_database(name) #:nodoc:
295
+ def drop_database(name) # :nodoc:
274
296
  execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
275
297
  end
276
298
 
@@ -309,7 +331,8 @@ module ActiveRecord
309
331
  #
310
332
  # Example:
311
333
  # rename_table('octopuses', 'octopi')
312
- def rename_table(table_name, new_name)
334
+ def rename_table(table_name, new_name, **options)
335
+ validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
313
336
  schema_cache.clear_data_source_cache!(table_name.to_s)
314
337
  schema_cache.clear_data_source_cache!(new_name.to_s)
315
338
  execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
@@ -346,12 +369,21 @@ module ActiveRecord
346
369
  end
347
370
  end
348
371
 
349
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
372
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
373
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_default_for_alter(table_name, column_name, default_or_changes)}"
374
+ end
375
+
376
+ def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
377
+ column = column_for(table_name, column_name)
378
+ return unless column
379
+
350
380
  default = extract_new_default_value(default_or_changes)
351
- change_column table_name, column_name, nil, default: default
381
+ ChangeColumnDefaultDefinition.new(column, default)
352
382
  end
353
383
 
354
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
384
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
385
+ validate_change_column_null_argument!(null)
386
+
355
387
  unless null || default.nil?
356
388
  execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
357
389
  end
@@ -364,22 +396,64 @@ module ActiveRecord
364
396
  change_column table_name, column_name, nil, comment: comment
365
397
  end
366
398
 
367
- def change_column(table_name, column_name, type, **options) #:nodoc:
399
+ def change_column(table_name, column_name, type, **options) # :nodoc:
368
400
  execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
369
401
  end
370
402
 
371
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
403
+ # Builds a ChangeColumnDefinition object.
404
+ #
405
+ # This definition object contains information about the column change that would occur
406
+ # if the same arguments were passed to #change_column. See #change_column for information about
407
+ # passing a +table_name+, +column_name+, +type+ and other options that can be passed.
408
+ def build_change_column_definition(table_name, column_name, type, **options) # :nodoc:
409
+ column = column_for(table_name, column_name)
410
+ type ||= column.sql_type
411
+
412
+ unless options.key?(:default)
413
+ options[:default] = column.default
414
+ end
415
+
416
+ unless options.key?(:null)
417
+ options[:null] = column.null
418
+ end
419
+
420
+ unless options.key?(:comment)
421
+ options[:comment] = column.comment
422
+ end
423
+
424
+ if options[:collation] == :no_collation
425
+ options.delete(:collation)
426
+ else
427
+ options[:collation] ||= column.collation if text_type?(type)
428
+ end
429
+
430
+ unless options.key?(:auto_increment)
431
+ options[:auto_increment] = column.auto_increment?
432
+ end
433
+
434
+ td = create_table_definition(table_name)
435
+ cd = td.new_column_definition(column.name, type, **options)
436
+ ChangeColumnDefinition.new(cd, column.name)
437
+ end
438
+
439
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
372
440
  execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
373
441
  rename_column_indexes(table_name, column_name, new_column_name)
374
442
  end
375
443
 
376
- def add_index(table_name, column_name, **options) #:nodoc:
444
+ def add_index(table_name, column_name, **options) # :nodoc:
445
+ create_index = build_create_index_definition(table_name, column_name, **options)
446
+ return unless create_index
447
+
448
+ execute schema_creation.accept(create_index)
449
+ end
450
+
451
+ def build_create_index_definition(table_name, column_name, **options) # :nodoc:
377
452
  index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
378
453
 
379
454
  return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
380
455
 
381
- create_index = CreateIndexDefinition.new(index, algorithm)
382
- execute schema_creation.accept(create_index)
456
+ CreateIndexDefinition.new(index, algorithm)
383
457
  end
384
458
 
385
459
  def add_sql_comment!(sql, comment) # :nodoc:
@@ -392,11 +466,13 @@ module ActiveRecord
392
466
 
393
467
  scope = quoted_scope(table_name)
394
468
 
395
- fk_info = exec_query(<<~SQL, "SCHEMA")
469
+ # MySQL returns 1 row for each column of composite foreign keys.
470
+ fk_info = internal_exec_query(<<~SQL, "SCHEMA")
396
471
  SELECT fk.referenced_table_name AS 'to_table',
397
472
  fk.referenced_column_name AS 'primary_key',
398
473
  fk.column_name AS 'column',
399
474
  fk.constraint_name AS 'name',
475
+ fk.ordinal_position AS 'position',
400
476
  rc.update_rule AS 'on_update',
401
477
  rc.delete_rule AS 'on_delete'
402
478
  FROM information_schema.referential_constraints rc
@@ -409,17 +485,24 @@ module ActiveRecord
409
485
  AND rc.table_name = #{scope[:name]}
410
486
  SQL
411
487
 
412
- fk_info.map do |row|
488
+ grouped_fk = fk_info.group_by { |row| row["name"] }.values.each { |group| group.sort_by! { |row| row["position"] } }
489
+ grouped_fk.map do |group|
490
+ row = group.first
413
491
  options = {
414
- column: row["column"],
415
492
  name: row["name"],
416
- primary_key: row["primary_key"]
493
+ on_update: extract_foreign_key_action(row["on_update"]),
494
+ on_delete: extract_foreign_key_action(row["on_delete"])
417
495
  }
418
496
 
419
- options[:on_update] = extract_foreign_key_action(row["on_update"])
420
- options[:on_delete] = extract_foreign_key_action(row["on_delete"])
497
+ if group.one?
498
+ options[:column] = unquote_identifier(row["column"])
499
+ options[:primary_key] = row["primary_key"]
500
+ else
501
+ options[:column] = group.map { |row| unquote_identifier(row["column"]) }
502
+ options[:primary_key] = group.map { |row| row["primary_key"] }
503
+ end
421
504
 
422
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
505
+ ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
423
506
  end
424
507
  end
425
508
 
@@ -427,7 +510,7 @@ module ActiveRecord
427
510
  if supports_check_constraints?
428
511
  scope = quoted_scope(table_name)
429
512
 
430
- chk_info = exec_query(<<~SQL, "SCHEMA")
513
+ sql = <<~SQL
431
514
  SELECT cc.constraint_name AS 'name',
432
515
  cc.check_clause AS 'expression'
433
516
  FROM information_schema.check_constraints cc
@@ -437,13 +520,24 @@ module ActiveRecord
437
520
  AND tc.table_name = #{scope[:name]}
438
521
  AND cc.constraint_schema = #{scope[:schema]}
439
522
  SQL
523
+ sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
524
+
525
+ chk_info = internal_exec_query(sql, "SCHEMA")
440
526
 
441
527
  chk_info.map do |row|
442
528
  options = {
443
529
  name: row["name"]
444
530
  }
445
531
  expression = row["expression"]
446
- expression = expression[1..-2] unless mariadb? # remove parentheses added by mysql
532
+ expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
533
+ expression = strip_whitespace_characters(expression)
534
+
535
+ unless mariadb?
536
+ # MySQL returns check constraints expression in an already escaped form.
537
+ # This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
538
+ expression = expression.gsub("\\'", "'")
539
+ end
540
+
447
541
  CheckConstraintDefinition.new(table_name, expression, options)
448
542
  end
449
543
  else
@@ -548,8 +642,12 @@ module ActiveRecord
548
642
  sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
549
643
  elsif insert.update_duplicates?
550
644
  sql << " ON DUPLICATE KEY UPDATE "
551
- sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
552
- sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
645
+ if insert.raw_update_sql?
646
+ sql << insert.raw_update_sql
647
+ else
648
+ sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
649
+ sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
650
+ end
553
651
  end
554
652
 
555
653
  sql
@@ -561,58 +659,99 @@ module ActiveRecord
561
659
  end
562
660
  end
563
661
 
564
- private
565
- def initialize_type_map(m = type_map)
566
- super
662
+ class << self
663
+ def extended_type_map(default_timezone: nil, emulate_booleans:) # :nodoc:
664
+ super(default_timezone: default_timezone).tap do |m|
665
+ if emulate_booleans
666
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new
667
+ end
668
+ end
669
+ end
670
+
671
+ private
672
+ def initialize_type_map(m)
673
+ super
674
+
675
+ m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
676
+ m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
677
+ m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
678
+ m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
679
+ m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
680
+ m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
681
+ m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
682
+ m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
683
+ m.register_type %r(^float)i, Type::Float.new(limit: 24)
684
+ m.register_type %r(^double)i, Type::Float.new(limit: 53)
685
+
686
+ register_integer_type m, %r(^bigint)i, limit: 8
687
+ register_integer_type m, %r(^int)i, limit: 4
688
+ register_integer_type m, %r(^mediumint)i, limit: 3
689
+ register_integer_type m, %r(^smallint)i, limit: 2
690
+ register_integer_type m, %r(^tinyint)i, limit: 1
691
+
692
+ m.alias_type %r(year)i, "integer"
693
+ m.alias_type %r(bit)i, "binary"
694
+ end
567
695
 
568
- m.register_type(%r(char)i) do |sql_type|
569
- limit = extract_limit(sql_type)
570
- Type.lookup(:string, adapter: :mysql2, limit: limit)
696
+ def register_integer_type(mapping, key, **options)
697
+ mapping.register_type(key) do |sql_type|
698
+ if /\bunsigned\b/.match?(sql_type)
699
+ Type::UnsignedInteger.new(**options)
700
+ else
701
+ Type::Integer.new(**options)
702
+ end
703
+ end
571
704
  end
572
705
 
573
- m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
574
- m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
575
- m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
576
- m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
577
- m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
578
- m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
579
- m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
580
- m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
581
- m.register_type %r(^float)i, Type::Float.new(limit: 24)
582
- m.register_type %r(^double)i, Type::Float.new(limit: 53)
583
-
584
- register_integer_type m, %r(^bigint)i, limit: 8
585
- register_integer_type m, %r(^int)i, limit: 4
586
- register_integer_type m, %r(^mediumint)i, limit: 3
587
- register_integer_type m, %r(^smallint)i, limit: 2
588
- register_integer_type m, %r(^tinyint)i, limit: 1
589
-
590
- m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
591
- m.alias_type %r(year)i, "integer"
592
- m.alias_type %r(bit)i, "binary"
593
-
594
- m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
595
- m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
596
- end
597
-
598
- def register_integer_type(mapping, key, **options)
599
- mapping.register_type(key) do |sql_type|
600
- if /\bunsigned\b/.match?(sql_type)
601
- Type::UnsignedInteger.new(**options)
706
+ def extract_precision(sql_type)
707
+ if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
708
+ super || 0
602
709
  else
603
- Type::Integer.new(**options)
710
+ super
604
711
  end
605
712
  end
713
+ end
714
+
715
+ EXTENDED_TYPE_MAPS = Concurrent::Map.new
716
+ EMULATE_BOOLEANS_TRUE = { emulate_booleans: true }.freeze
717
+
718
+ private
719
+ def strip_whitespace_characters(expression)
720
+ expression = expression.gsub(/\\n|\\\\/, "")
721
+ expression = expression.gsub(/\s{2,}/, " ")
722
+ expression
606
723
  end
607
724
 
608
- def extract_precision(sql_type)
609
- if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
610
- super || 0
611
- else
612
- super
725
+ def extended_type_map_key
726
+ if @default_timezone
727
+ { default_timezone: @default_timezone, emulate_booleans: emulate_booleans }
728
+ elsif emulate_booleans
729
+ EMULATE_BOOLEANS_TRUE
613
730
  end
614
731
  end
615
732
 
733
+ def handle_warnings(sql)
734
+ return if ActiveRecord.db_warnings_action.nil? || @raw_connection.warning_count == 0
735
+
736
+ @affected_rows_before_warnings = @raw_connection.affected_rows
737
+ result = @raw_connection.query("SHOW WARNINGS")
738
+ result.each do |level, code, message|
739
+ warning = SQLWarning.new(message, code, level, sql, @pool)
740
+ next if warning_ignored?(warning)
741
+
742
+ ActiveRecord.db_warnings_action.call(warning)
743
+ end
744
+ end
745
+
746
+ def warning_ignored?(warning)
747
+ warning.level == "Note" || super
748
+ end
749
+
750
+ # Make sure we carry over any changes to ActiveRecord.default_timezone that have been
751
+ # made since we established the connection
752
+ def sync_timezone_changes(raw_connection)
753
+ end
754
+
616
755
  # See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
617
756
  ER_DB_CREATE_EXISTS = 1007
618
757
  ER_FILSORT_ABORT = 1028
@@ -630,69 +769,59 @@ module ActiveRecord
630
769
  ER_CANNOT_CREATE_TABLE = 1005
631
770
  ER_LOCK_WAIT_TIMEOUT = 1205
632
771
  ER_QUERY_INTERRUPTED = 1317
772
+ ER_CONNECTION_KILLED = 1927
773
+ CR_SERVER_GONE_ERROR = 2006
774
+ CR_SERVER_LOST = 2013
633
775
  ER_QUERY_TIMEOUT = 3024
634
776
  ER_FK_INCOMPATIBLE_COLUMNS = 3780
777
+ ER_CLIENT_INTERACTION_TIMEOUT = 4031
635
778
 
636
779
  def translate_exception(exception, message:, sql:, binds:)
637
780
  case error_number(exception)
638
781
  when nil
639
782
  if exception.message.match?(/MySQL client is not connected/i)
640
- ConnectionNotEstablished.new(exception)
783
+ ConnectionNotEstablished.new(exception, connection_pool: @pool)
641
784
  else
642
785
  super
643
786
  end
787
+ when ER_CONNECTION_KILLED, CR_SERVER_GONE_ERROR, CR_SERVER_LOST, ER_CLIENT_INTERACTION_TIMEOUT
788
+ ConnectionFailed.new(message, sql: sql, binds: binds, connection_pool: @pool)
644
789
  when ER_DB_CREATE_EXISTS
645
- DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
790
+ DatabaseAlreadyExists.new(message, sql: sql, binds: binds, connection_pool: @pool)
646
791
  when ER_DUP_ENTRY
647
- RecordNotUnique.new(message, sql: sql, binds: binds)
792
+ RecordNotUnique.new(message, sql: sql, binds: binds, connection_pool: @pool)
648
793
  when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
649
- InvalidForeignKey.new(message, sql: sql, binds: binds)
794
+ InvalidForeignKey.new(message, sql: sql, binds: binds, connection_pool: @pool)
650
795
  when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
651
- mismatched_foreign_key(message, sql: sql, binds: binds)
796
+ mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
652
797
  when ER_CANNOT_CREATE_TABLE
653
798
  if message.include?("errno: 150")
654
- mismatched_foreign_key(message, sql: sql, binds: binds)
799
+ mismatched_foreign_key(message, sql: sql, binds: binds, connection_pool: @pool)
655
800
  else
656
801
  super
657
802
  end
658
803
  when ER_DATA_TOO_LONG
659
- ValueTooLong.new(message, sql: sql, binds: binds)
804
+ ValueTooLong.new(message, sql: sql, binds: binds, connection_pool: @pool)
660
805
  when ER_OUT_OF_RANGE
661
- RangeError.new(message, sql: sql, binds: binds)
806
+ RangeError.new(message, sql: sql, binds: binds, connection_pool: @pool)
662
807
  when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
663
- NotNullViolation.new(message, sql: sql, binds: binds)
808
+ NotNullViolation.new(message, sql: sql, binds: binds, connection_pool: @pool)
664
809
  when ER_LOCK_DEADLOCK
665
- Deadlocked.new(message, sql: sql, binds: binds)
810
+ Deadlocked.new(message, sql: sql, binds: binds, connection_pool: @pool)
666
811
  when ER_LOCK_WAIT_TIMEOUT
667
- LockWaitTimeout.new(message, sql: sql, binds: binds)
812
+ LockWaitTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
668
813
  when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
669
- StatementTimeout.new(message, sql: sql, binds: binds)
814
+ StatementTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
670
815
  when ER_QUERY_INTERRUPTED
671
- QueryCanceled.new(message, sql: sql, binds: binds)
816
+ QueryCanceled.new(message, sql: sql, binds: binds, connection_pool: @pool)
672
817
  else
673
818
  super
674
819
  end
675
820
  end
676
821
 
677
822
  def change_column_for_alter(table_name, column_name, type, **options)
678
- column = column_for(table_name, column_name)
679
- type ||= column.sql_type
680
-
681
- unless options.key?(:default)
682
- options[:default] = column.default
683
- end
684
-
685
- unless options.key?(:null)
686
- options[:null] = column.null
687
- end
688
-
689
- unless options.key?(:comment)
690
- options[:comment] = column.comment
691
- end
692
-
693
- td = create_table_definition(table_name)
694
- cd = td.new_column_definition(column.name, type, **options)
695
- schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
823
+ cd = build_change_column_definition(table_name, column_name, type, **options)
824
+ schema_creation.accept(cd)
696
825
  end
697
826
 
698
827
  def rename_column_for_alter(table_name, column_name, new_column_name)
@@ -706,7 +835,7 @@ module ActiveRecord
706
835
  comment: column.comment
707
836
  }
708
837
 
709
- current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
838
+ current_type = internal_exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
710
839
  td = create_table_definition(table_name)
711
840
  cd = td.new_column_definition(new_column_name, current_type, **options)
712
841
  schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
@@ -743,9 +872,6 @@ module ActiveRecord
743
872
  def configure_connection
744
873
  variables = @config.fetch(:variables, {}).stringify_keys
745
874
 
746
- # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
747
- variables["sql_auto_is_null"] = 0
748
-
749
875
  # Increase timeout so the server doesn't disconnect us.
750
876
  wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
751
877
  wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
@@ -780,17 +906,16 @@ module ActiveRecord
780
906
  end
781
907
 
782
908
  # Gather up all of the SET variables...
783
- variable_assignments = variables.map do |k, v|
909
+ variable_assignments = variables.filter_map do |k, v|
784
910
  if defaults.include?(v)
785
911
  "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
786
912
  elsif !v.nil?
787
913
  "@@SESSION.#{k} = #{quote(v)}"
788
914
  end
789
- # or else nil; compact to clear nils out
790
- end.compact.join(", ")
915
+ end.join(", ")
791
916
 
792
917
  # ...and send them all in one query
793
- execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
918
+ internal_execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}")
794
919
  end
795
920
 
796
921
  def column_definitions(table_name) # :nodoc:
@@ -800,7 +925,7 @@ module ActiveRecord
800
925
  end
801
926
 
802
927
  def create_table_info(table_name) # :nodoc:
803
- exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
928
+ internal_exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
804
929
  end
805
930
 
806
931
  def arel_visitor
@@ -811,18 +936,17 @@ module ActiveRecord
811
936
  StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
812
937
  end
813
938
 
814
- def mismatched_foreign_key(message, sql:, binds:)
939
+ def mismatched_foreign_key_details(message:, sql:)
940
+ foreign_key_pat =
941
+ /Referencing column '(\w+)' and referenced/i =~ message ? $1 : '\w+'
942
+
815
943
  match = %r/
816
944
  (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
817
- FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
945
+ FOREIGN\s+KEY\s*\(`?(?<foreign_key>#{foreign_key_pat})`?\)\s*
818
946
  REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
819
947
  /xmi.match(sql)
820
948
 
821
- options = {
822
- message: message,
823
- sql: sql,
824
- binds: binds,
825
- }
949
+ options = {}
826
950
 
827
951
  if match
828
952
  options[:table] = match[:table]
@@ -832,24 +956,29 @@ module ActiveRecord
832
956
  options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
833
957
  end
834
958
 
835
- MismatchedForeignKey.new(**options)
959
+ options
836
960
  end
837
961
 
838
- def version_string(full_version_string)
839
- full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
840
- end
962
+ def mismatched_foreign_key(message, sql:, binds:, connection_pool:)
963
+ options = {
964
+ message: message,
965
+ sql: sql,
966
+ binds: binds,
967
+ connection_pool: connection_pool
968
+ }
841
969
 
842
- # Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
843
- # TODO: Remove the constant alias once Rails 6.1 has released.
844
- MysqlString = Type::String # :nodoc:
970
+ if sql
971
+ options.update mismatched_foreign_key_details(message: message, sql: sql)
972
+ else
973
+ options[:query_parser] = ->(sql) { mismatched_foreign_key_details(message: message, sql: sql) }
974
+ end
845
975
 
846
- ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
847
- Type::ImmutableString.new(true: "1", false: "0", **args)
976
+ MismatchedForeignKey.new(**options)
848
977
  end
849
- ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
850
- Type::String.new(true: "1", false: "0", **args)
978
+
979
+ def version_string(full_version_string)
980
+ full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
851
981
  end
852
- ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
853
982
  end
854
983
  end
855
984
  end