activerecord 5.0.6 → 6.0.1

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

Potentially problematic release.


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

Files changed (358) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +638 -2023
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +8 -6
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record/aggregations.rb +249 -246
  8. data/lib/active_record/association_relation.rb +24 -13
  9. data/lib/active_record/associations/alias_tracker.rb +24 -33
  10. data/lib/active_record/associations/association.rb +119 -56
  11. data/lib/active_record/associations/association_scope.rb +94 -94
  12. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +18 -25
  15. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  16. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
  18. data/lib/active_record/associations/builder/has_many.rb +4 -0
  19. data/lib/active_record/associations/builder/has_one.rb +37 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  21. data/lib/active_record/associations/collection_association.rb +80 -252
  22. data/lib/active_record/associations/collection_proxy.rb +158 -121
  23. data/lib/active_record/associations/foreign_association.rb +9 -0
  24. data/lib/active_record/associations/has_many_association.rb +23 -29
  25. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  26. data/lib/active_record/associations/has_one_association.rb +59 -54
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -176
  32. data/lib/active_record/associations/preloader/association.rb +84 -125
  33. data/lib/active_record/associations/preloader/through_association.rb +82 -75
  34. data/lib/active_record/associations/preloader.rb +90 -102
  35. data/lib/active_record/associations/singular_association.rb +12 -45
  36. data/lib/active_record/associations/through_association.rb +26 -14
  37. data/lib/active_record/associations.rb +1603 -1592
  38. data/lib/active_record/attribute_assignment.rb +54 -60
  39. data/lib/active_record/attribute_decorators.rb +38 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -91
  43. data/lib/active_record/attribute_methods/query.rb +4 -3
  44. data/lib/active_record/attribute_methods/read.rb +21 -49
  45. data/lib/active_record/attribute_methods/serialization.rb +30 -7
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
  47. data/lib/active_record/attribute_methods/write.rb +35 -33
  48. data/lib/active_record/attribute_methods.rb +66 -106
  49. data/lib/active_record/attributes.rb +38 -24
  50. data/lib/active_record/autosave_association.rb +53 -32
  51. data/lib/active_record/base.rb +27 -24
  52. data/lib/active_record/callbacks.rb +63 -33
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -11
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
  68. data/lib/active_record/connection_adapters/column.rb +41 -13
  69. data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  71. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  98. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
  116. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
  126. data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
  127. data/lib/active_record/connection_handling.rb +159 -40
  128. data/lib/active_record/core.rb +202 -162
  129. data/lib/active_record/counter_cache.rb +57 -28
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +87 -86
  136. data/lib/active_record/enum.rb +60 -23
  137. data/lib/active_record/errors.rb +114 -18
  138. data/lib/active_record/explain.rb +4 -3
  139. data/lib/active_record/explain_registry.rb +3 -1
  140. data/lib/active_record/explain_subscriber.rb +9 -4
  141. data/lib/active_record/fixture_set/file.rb +13 -8
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +195 -502
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +151 -97
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +116 -25
  151. data/lib/active_record/internal_metadata.rb +15 -18
  152. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  153. data/lib/active_record/locking/optimistic.rb +78 -87
  154. data/lib/active_record/locking/pessimistic.rb +18 -6
  155. data/lib/active_record/log_subscriber.rb +48 -29
  156. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  157. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/migration/command_recorder.rb +143 -97
  160. data/lib/active_record/migration/compatibility.rb +174 -56
  161. data/lib/active_record/migration/join_table.rb +8 -6
  162. data/lib/active_record/migration.rb +367 -300
  163. data/lib/active_record/model_schema.rb +145 -139
  164. data/lib/active_record/nested_attributes.rb +214 -201
  165. data/lib/active_record/no_touching.rb +10 -1
  166. data/lib/active_record/null_relation.rb +13 -34
  167. data/lib/active_record/persistence.rb +442 -72
  168. data/lib/active_record/query_cache.rb +15 -14
  169. data/lib/active_record/querying.rb +36 -23
  170. data/lib/active_record/railtie.rb +128 -36
  171. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  172. data/lib/active_record/railties/console_sandbox.rb +2 -0
  173. data/lib/active_record/railties/controller_runtime.rb +34 -33
  174. data/lib/active_record/railties/databases.rake +309 -177
  175. data/lib/active_record/readonly_attributes.rb +5 -4
  176. data/lib/active_record/reflection.rb +211 -249
  177. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  178. data/lib/active_record/relation/batches.rb +99 -52
  179. data/lib/active_record/relation/calculations.rb +211 -172
  180. data/lib/active_record/relation/delegation.rb +67 -65
  181. data/lib/active_record/relation/finder_methods.rb +208 -247
  182. data/lib/active_record/relation/from_clause.rb +2 -8
  183. data/lib/active_record/relation/merger.rb +78 -61
  184. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  185. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  186. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  187. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  188. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  189. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  190. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  191. data/lib/active_record/relation/predicate_builder.rb +86 -104
  192. data/lib/active_record/relation/query_attribute.rb +33 -2
  193. data/lib/active_record/relation/query_methods.rb +458 -329
  194. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  195. data/lib/active_record/relation/spawn_methods.rb +8 -7
  196. data/lib/active_record/relation/where_clause.rb +111 -95
  197. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  198. data/lib/active_record/relation.rb +429 -318
  199. data/lib/active_record/result.rb +69 -39
  200. data/lib/active_record/runtime_registry.rb +5 -3
  201. data/lib/active_record/sanitization.rb +83 -99
  202. data/lib/active_record/schema.rb +7 -14
  203. data/lib/active_record/schema_dumper.rb +71 -69
  204. data/lib/active_record/schema_migration.rb +15 -5
  205. data/lib/active_record/scoping/default.rb +93 -95
  206. data/lib/active_record/scoping/named.rb +45 -25
  207. data/lib/active_record/scoping.rb +20 -19
  208. data/lib/active_record/secure_token.rb +4 -2
  209. data/lib/active_record/serialization.rb +2 -0
  210. data/lib/active_record/statement_cache.rb +63 -28
  211. data/lib/active_record/store.rb +121 -41
  212. data/lib/active_record/suppressor.rb +4 -1
  213. data/lib/active_record/table_metadata.rb +26 -20
  214. data/lib/active_record/tasks/database_tasks.rb +276 -85
  215. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
  216. data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
  217. data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
  218. data/lib/active_record/test_databases.rb +23 -0
  219. data/lib/active_record/test_fixtures.rb +224 -0
  220. data/lib/active_record/timestamp.rb +70 -35
  221. data/lib/active_record/touch_later.rb +7 -4
  222. data/lib/active_record/transactions.rb +133 -149
  223. data/lib/active_record/translation.rb +3 -1
  224. data/lib/active_record/type/adapter_specific_registry.rb +44 -45
  225. data/lib/active_record/type/date.rb +2 -0
  226. data/lib/active_record/type/date_time.rb +2 -0
  227. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  228. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  229. data/lib/active_record/type/internal/timezone.rb +2 -0
  230. data/lib/active_record/type/json.rb +30 -0
  231. data/lib/active_record/type/serialized.rb +16 -8
  232. data/lib/active_record/type/text.rb +11 -0
  233. data/lib/active_record/type/time.rb +2 -1
  234. data/lib/active_record/type/type_map.rb +13 -15
  235. data/lib/active_record/type/unsigned_integer.rb +17 -0
  236. data/lib/active_record/type.rb +23 -17
  237. data/lib/active_record/type_caster/connection.rb +17 -12
  238. data/lib/active_record/type_caster/map.rb +5 -4
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/validations/absence.rb +2 -0
  241. data/lib/active_record/validations/associated.rb +3 -1
  242. data/lib/active_record/validations/length.rb +2 -0
  243. data/lib/active_record/validations/presence.rb +4 -2
  244. data/lib/active_record/validations/uniqueness.rb +29 -42
  245. data/lib/active_record/validations.rb +7 -4
  246. data/lib/active_record/version.rb +3 -1
  247. data/lib/active_record.rb +36 -22
  248. data/lib/arel/alias_predication.rb +9 -0
  249. data/lib/arel/attributes/attribute.rb +37 -0
  250. data/lib/arel/attributes.rb +22 -0
  251. data/lib/arel/collectors/bind.rb +24 -0
  252. data/lib/arel/collectors/composite.rb +31 -0
  253. data/lib/arel/collectors/plain_string.rb +20 -0
  254. data/lib/arel/collectors/sql_string.rb +20 -0
  255. data/lib/arel/collectors/substitute_binds.rb +28 -0
  256. data/lib/arel/crud.rb +42 -0
  257. data/lib/arel/delete_manager.rb +18 -0
  258. data/lib/arel/errors.rb +9 -0
  259. data/lib/arel/expressions.rb +29 -0
  260. data/lib/arel/factory_methods.rb +49 -0
  261. data/lib/arel/insert_manager.rb +49 -0
  262. data/lib/arel/math.rb +45 -0
  263. data/lib/arel/nodes/and.rb +32 -0
  264. data/lib/arel/nodes/ascending.rb +23 -0
  265. data/lib/arel/nodes/binary.rb +52 -0
  266. data/lib/arel/nodes/bind_param.rb +36 -0
  267. data/lib/arel/nodes/case.rb +55 -0
  268. data/lib/arel/nodes/casted.rb +50 -0
  269. data/lib/arel/nodes/comment.rb +29 -0
  270. data/lib/arel/nodes/count.rb +12 -0
  271. data/lib/arel/nodes/delete_statement.rb +45 -0
  272. data/lib/arel/nodes/descending.rb +23 -0
  273. data/lib/arel/nodes/equality.rb +18 -0
  274. data/lib/arel/nodes/extract.rb +24 -0
  275. data/lib/arel/nodes/false.rb +16 -0
  276. data/lib/arel/nodes/full_outer_join.rb +8 -0
  277. data/lib/arel/nodes/function.rb +44 -0
  278. data/lib/arel/nodes/grouping.rb +8 -0
  279. data/lib/arel/nodes/in.rb +8 -0
  280. data/lib/arel/nodes/infix_operation.rb +80 -0
  281. data/lib/arel/nodes/inner_join.rb +8 -0
  282. data/lib/arel/nodes/insert_statement.rb +37 -0
  283. data/lib/arel/nodes/join_source.rb +20 -0
  284. data/lib/arel/nodes/matches.rb +18 -0
  285. data/lib/arel/nodes/named_function.rb +23 -0
  286. data/lib/arel/nodes/node.rb +50 -0
  287. data/lib/arel/nodes/node_expression.rb +13 -0
  288. data/lib/arel/nodes/outer_join.rb +8 -0
  289. data/lib/arel/nodes/over.rb +15 -0
  290. data/lib/arel/nodes/regexp.rb +16 -0
  291. data/lib/arel/nodes/right_outer_join.rb +8 -0
  292. data/lib/arel/nodes/select_core.rb +67 -0
  293. data/lib/arel/nodes/select_statement.rb +41 -0
  294. data/lib/arel/nodes/sql_literal.rb +16 -0
  295. data/lib/arel/nodes/string_join.rb +11 -0
  296. data/lib/arel/nodes/table_alias.rb +27 -0
  297. data/lib/arel/nodes/terminal.rb +16 -0
  298. data/lib/arel/nodes/true.rb +16 -0
  299. data/lib/arel/nodes/unary.rb +45 -0
  300. data/lib/arel/nodes/unary_operation.rb +20 -0
  301. data/lib/arel/nodes/unqualified_column.rb +22 -0
  302. data/lib/arel/nodes/update_statement.rb +41 -0
  303. data/lib/arel/nodes/values_list.rb +9 -0
  304. data/lib/arel/nodes/window.rb +126 -0
  305. data/lib/arel/nodes/with.rb +11 -0
  306. data/lib/arel/nodes.rb +68 -0
  307. data/lib/arel/order_predications.rb +13 -0
  308. data/lib/arel/predications.rb +257 -0
  309. data/lib/arel/select_manager.rb +271 -0
  310. data/lib/arel/table.rb +110 -0
  311. data/lib/arel/tree_manager.rb +72 -0
  312. data/lib/arel/update_manager.rb +34 -0
  313. data/lib/arel/visitors/depth_first.rb +204 -0
  314. data/lib/arel/visitors/dot.rb +297 -0
  315. data/lib/arel/visitors/ibm_db.rb +34 -0
  316. data/lib/arel/visitors/informix.rb +62 -0
  317. data/lib/arel/visitors/mssql.rb +157 -0
  318. data/lib/arel/visitors/mysql.rb +83 -0
  319. data/lib/arel/visitors/oracle.rb +159 -0
  320. data/lib/arel/visitors/oracle12.rb +66 -0
  321. data/lib/arel/visitors/postgresql.rb +110 -0
  322. data/lib/arel/visitors/sqlite.rb +39 -0
  323. data/lib/arel/visitors/to_sql.rb +889 -0
  324. data/lib/arel/visitors/visitor.rb +46 -0
  325. data/lib/arel/visitors/where_sql.rb +23 -0
  326. data/lib/arel/visitors.rb +20 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +58 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  332. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  334. data/lib/rails/generators/active_record/migration.rb +17 -2
  335. data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
  336. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  337. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +133 -50
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  350. data/lib/active_record/attribute_set/builder.rb +0 -130
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/collection_cache_key.rb +0 -50
  353. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  354. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  355. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  356. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  357. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  358. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,32 +1,21 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
- require 'active_record/connection_adapters/mysql/column'
4
- require 'active_record/connection_adapters/mysql/explain_pretty_printer'
5
- require 'active_record/connection_adapters/mysql/quoting'
6
- require 'active_record/connection_adapters/mysql/schema_creation'
7
- require 'active_record/connection_adapters/mysql/schema_definitions'
8
- require 'active_record/connection_adapters/mysql/schema_dumper'
9
- require 'active_record/connection_adapters/mysql/type_metadata'
10
-
11
- require 'active_support/core_ext/string/strip'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/connection_adapters/abstract_adapter"
4
+ require "active_record/connection_adapters/statement_pool"
5
+ require "active_record/connection_adapters/mysql/column"
6
+ require "active_record/connection_adapters/mysql/explain_pretty_printer"
7
+ require "active_record/connection_adapters/mysql/quoting"
8
+ require "active_record/connection_adapters/mysql/schema_creation"
9
+ require "active_record/connection_adapters/mysql/schema_definitions"
10
+ require "active_record/connection_adapters/mysql/schema_dumper"
11
+ require "active_record/connection_adapters/mysql/schema_statements"
12
+ require "active_record/connection_adapters/mysql/type_metadata"
12
13
 
13
14
  module ActiveRecord
14
15
  module ConnectionAdapters
15
16
  class AbstractMysqlAdapter < AbstractAdapter
16
17
  include MySQL::Quoting
17
- include MySQL::ColumnDumper
18
-
19
- def update_table_definition(table_name, base) # :nodoc:
20
- MySQL::Table.new(table_name, base)
21
- end
22
-
23
- def schema_creation # :nodoc:
24
- MySQL::SchemaCreation.new(self)
25
- end
26
-
27
- def arel_visitor # :nodoc:
28
- Arel::Visitors::MySQL.new(self)
29
- end
18
+ include MySQL::SchemaStatements
30
19
 
31
20
  ##
32
21
  # :singleton-method:
@@ -35,82 +24,57 @@ module ActiveRecord
35
24
  # to your application.rb file:
36
25
  #
37
26
  # ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = false
38
- class_attribute :emulate_booleans
39
- self.emulate_booleans = true
27
+ class_attribute :emulate_booleans, default: true
40
28
 
41
29
  NATIVE_DATABASE_TYPES = {
42
- primary_key: "int auto_increment PRIMARY KEY",
30
+ primary_key: "bigint auto_increment PRIMARY KEY",
43
31
  string: { name: "varchar", limit: 255 },
44
32
  text: { name: "text" },
45
33
  integer: { name: "int", limit: 4 },
46
- float: { name: "float" },
34
+ float: { name: "float", limit: 24 },
47
35
  decimal: { name: "decimal" },
48
36
  datetime: { name: "datetime" },
37
+ timestamp: { name: "timestamp" },
49
38
  time: { name: "time" },
50
39
  date: { name: "date" },
51
40
  binary: { name: "blob" },
41
+ blob: { name: "blob" },
52
42
  boolean: { name: "tinyint", limit: 1 },
53
43
  json: { name: "json" },
54
44
  }
55
45
 
56
- INDEX_TYPES = [:fulltext, :spatial]
57
- INDEX_USINGS = [:btree, :hash]
46
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
47
+ private
58
48
 
59
- class StatementPool < ConnectionAdapters::StatementPool
60
- private def dealloc(stmt)
61
- stmt[:stmt].close
62
- end
49
+ def dealloc(stmt)
50
+ stmt.close
51
+ end
63
52
  end
64
53
 
65
54
  def initialize(connection, logger, connection_options, config)
66
55
  super(connection, logger, config)
67
-
68
- @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
69
-
70
- if version < '5.0.0'
71
- raise "Your version of MySQL (#{full_version.match(/^\d+\.\d+\.\d+/)[0]}) is too old. Active Record supports MySQL >= 5.0."
72
- end
73
56
  end
74
57
 
75
- CHARSETS_OF_4BYTES_MAXLEN = ['utf8mb4', 'utf16', 'utf16le', 'utf32']
76
-
77
- def internal_string_options_for_primary_key # :nodoc:
78
- super.tap { |options|
79
- options[:collation] = collation.sub(/\A[^_]+/, 'utf8') if CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
80
- }
81
- end
82
-
83
- def version #:nodoc:
84
- @version ||= Version.new(full_version.match(/^\d+\.\d+\.\d+/)[0])
58
+ def get_database_version #:nodoc:
59
+ full_version_string = get_full_version
60
+ version_string = version_string(full_version_string)
61
+ Version.new(version_string, full_version_string)
85
62
  end
86
63
 
87
64
  def mariadb? # :nodoc:
88
- full_version =~ /mariadb/i
89
- end
90
-
91
- # Returns true, since this connection adapter supports migrations.
92
- def supports_migrations?
93
- true
94
- end
95
-
96
- def supports_primary_key?
97
- true
65
+ /mariadb/i.match?(full_version)
98
66
  end
99
67
 
100
- def supports_bulk_alter? #:nodoc:
68
+ def supports_bulk_alter?
101
69
  true
102
70
  end
103
71
 
104
- # Returns true, since this connection adapter supports prepared statement
105
- # caching.
106
- def supports_statement_cache?
107
- true
72
+ def supports_index_sort_order?
73
+ !mariadb? && database_version >= "8.0.1"
108
74
  end
109
75
 
110
- # Technically MySQL allows to create indexes with the sort order syntax
111
- # but at the moment (5.5) it doesn't yet implement them
112
- def supports_index_sort_order?
113
- true
76
+ def supports_expression_index?
77
+ !mariadb? && database_version >= "8.0.13"
114
78
  end
115
79
 
116
80
  def supports_transaction_isolation?
@@ -134,10 +98,23 @@ module ActiveRecord
134
98
  end
135
99
 
136
100
  def supports_datetime_with_precision?
101
+ mariadb? || database_version >= "5.6.4"
102
+ end
103
+
104
+ def supports_virtual_columns?
105
+ mariadb? || database_version >= "5.7.5"
106
+ end
107
+
108
+ # See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
109
+ def supports_optimizer_hints?
110
+ !mariadb? && database_version >= "5.7.7"
111
+ end
112
+
113
+ def supports_common_table_expressions?
137
114
  if mariadb?
138
- version >= '5.3.0'
115
+ database_version >= "10.2.1"
139
116
  else
140
- version >= '5.6.4'
117
+ database_version >= "8.0.1"
141
118
  end
142
119
  end
143
120
 
@@ -145,12 +122,20 @@ module ActiveRecord
145
122
  true
146
123
  end
147
124
 
125
+ def supports_insert_on_duplicate_skip?
126
+ true
127
+ end
128
+
129
+ def supports_insert_on_duplicate_update?
130
+ true
131
+ end
132
+
148
133
  def get_advisory_lock(lock_name, timeout = 0) # :nodoc:
149
- select_value("SELECT GET_LOCK('#{lock_name}', #{timeout});").to_s == '1'
134
+ query_value("SELECT GET_LOCK(#{quote(lock_name.to_s)}, #{timeout})") == 1
150
135
  end
151
136
 
152
137
  def release_advisory_lock(lock_name) # :nodoc:
153
- select_value("SELECT RELEASE_LOCK('#{lock_name}')").to_s == '1'
138
+ query_value("SELECT RELEASE_LOCK(#{quote(lock_name.to_s)})") == 1
154
139
  end
155
140
 
156
141
  def native_database_types
@@ -158,7 +143,7 @@ module ActiveRecord
158
143
  end
159
144
 
160
145
  def index_algorithms
161
- { default: 'ALGORITHM = DEFAULT', copy: 'ALGORITHM = COPY', inplace: 'ALGORITHM = INPLACE' }
146
+ { default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
162
147
  end
163
148
 
164
149
  # HELPER METHODS ===========================================
@@ -169,10 +154,6 @@ module ActiveRecord
169
154
  raise NotImplementedError
170
155
  end
171
156
 
172
- def new_column(*args) #:nodoc:
173
- MySQL::Column.new(*args)
174
- end
175
-
176
157
  # Must return the MySQL error number from the exception, if the exception has an
177
158
  # error number.
178
159
  def error_number(exception) # :nodoc:
@@ -182,7 +163,7 @@ module ActiveRecord
182
163
  # REFERENTIAL INTEGRITY ====================================
183
164
 
184
165
  def disable_referential_integrity #:nodoc:
185
- old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
166
+ old = query_value("SELECT @@FOREIGN_KEY_CHECKS")
186
167
 
187
168
  begin
188
169
  update("SET FOREIGN_KEY_CHECKS = 0")
@@ -194,10 +175,9 @@ module ActiveRecord
194
175
 
195
176
  # CONNECTION MANAGEMENT ====================================
196
177
 
197
- # Clears the prepared statements cache.
198
- def clear_cache!
178
+ def clear_cache! # :nodoc:
199
179
  reload_type_map
200
- @statements.clear
180
+ super
201
181
  end
202
182
 
203
183
  #--
@@ -206,16 +186,22 @@ module ActiveRecord
206
186
 
207
187
  def explain(arel, binds = [])
208
188
  sql = "EXPLAIN #{to_sql(arel, binds)}"
209
- start = Time.now
210
- result = exec_query(sql, 'EXPLAIN', binds)
211
- elapsed = Time.now - start
189
+ start = Concurrent.monotonic_time
190
+ result = exec_query(sql, "EXPLAIN", binds)
191
+ elapsed = Concurrent.monotonic_time - start
212
192
 
213
193
  MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
214
194
  end
215
195
 
216
196
  # Executes the SQL statement in the context of this connection.
217
197
  def execute(sql, name = nil)
218
- log(sql, name) { @connection.query(sql) }
198
+ materialize_transactions
199
+
200
+ log(sql, name) do
201
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
202
+ @connection.query(sql)
203
+ end
204
+ end
219
205
  end
220
206
 
221
207
  # Mysql2Adapter doesn't have to free a result after using it, but we use this method
@@ -242,19 +228,7 @@ module ActiveRecord
242
228
  execute "ROLLBACK"
243
229
  end
244
230
 
245
- # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
246
- # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
247
- # these, we must use a subquery.
248
- def join_to_update(update, select, key) # :nodoc:
249
- if select.limit || select.offset || select.orders.any?
250
- super
251
- else
252
- update.table select.source
253
- update.wheres = select.constraints
254
- end
255
- end
256
-
257
- def empty_insert_statement_value
231
+ def empty_insert_statement_value(primary_key = nil)
258
232
  "VALUES ()"
259
233
  end
260
234
 
@@ -270,7 +244,7 @@ module ActiveRecord
270
244
  end
271
245
 
272
246
  # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
273
- # Charset defaults to utf8.
247
+ # Charset defaults to utf8mb4.
274
248
  #
275
249
  # Example:
276
250
  # create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin'
@@ -278,9 +252,13 @@ module ActiveRecord
278
252
  # create_database 'matt_development', charset: :big5
279
253
  def create_database(name, options = {})
280
254
  if options[:collation]
281
- execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset] || 'utf8')} COLLATE #{quote_table_name(options[:collation])}"
255
+ execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT COLLATE #{quote_table_name(options[:collation])}"
256
+ elsif options[:charset]
257
+ execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset])}"
258
+ elsif row_format_dynamic_by_default?
259
+ execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET `utf8mb4`"
282
260
  else
283
- execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset] || 'utf8')}"
261
+ raise "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
284
262
  end
285
263
  end
286
264
 
@@ -293,149 +271,34 @@ module ActiveRecord
293
271
  end
294
272
 
295
273
  def current_database
296
- select_value 'SELECT DATABASE() as db'
274
+ query_value("SELECT database()", "SCHEMA")
297
275
  end
298
276
 
299
277
  # Returns the database character set.
300
278
  def charset
301
- show_variable 'character_set_database'
279
+ show_variable "character_set_database"
302
280
  end
303
281
 
304
282
  # Returns the database collation strategy.
305
283
  def collation
306
- show_variable 'collation_database'
307
- end
308
-
309
- def tables(name = nil) # :nodoc:
310
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
311
- #tables currently returns both tables and views.
312
- This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
313
- Use #data_sources instead.
314
- MSG
315
-
316
- if name
317
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
318
- Passing arguments to #tables is deprecated without replacement.
319
- MSG
320
- end
321
-
322
- data_sources
323
- end
324
-
325
- def data_sources
326
- sql = "SELECT table_name FROM information_schema.tables "
327
- sql << "WHERE table_schema = DATABASE()"
328
-
329
- select_values(sql, 'SCHEMA')
330
- end
331
-
332
- def truncate(table_name, name = nil)
333
- execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
334
- end
335
-
336
- def table_exists?(table_name)
337
- # Update lib/active_record/internal_metadata.rb when this gets removed
338
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
339
- #table_exists? currently checks both tables and views.
340
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
341
- Use #data_source_exists? instead.
342
- MSG
343
-
344
- data_source_exists?(table_name)
345
- end
346
-
347
- def data_source_exists?(table_name)
348
- return false unless table_name.present?
349
-
350
- schema, name = extract_schema_qualified_name(table_name)
351
-
352
- sql = "SELECT table_name FROM information_schema.tables "
353
- sql << "WHERE table_schema = #{schema} AND table_name = #{name}"
354
-
355
- select_values(sql, 'SCHEMA').any?
356
- end
357
-
358
- def views # :nodoc:
359
- select_values("SHOW FULL TABLES WHERE table_type = 'VIEW'", 'SCHEMA')
360
- end
361
-
362
- def view_exists?(view_name) # :nodoc:
363
- return false unless view_name.present?
364
-
365
- schema, name = extract_schema_qualified_name(view_name)
366
-
367
- sql = "SELECT table_name FROM information_schema.tables WHERE table_type = 'VIEW'"
368
- sql << " AND table_schema = #{schema} AND table_name = #{name}"
369
-
370
- select_values(sql, 'SCHEMA').any?
371
- end
372
-
373
- # Returns an array of indexes for the given table.
374
- def indexes(table_name, name = nil) #:nodoc:
375
- indexes = []
376
- current_index = nil
377
- execute_and_free("SHOW KEYS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
378
- each_hash(result) do |row|
379
- if current_index != row[:Key_name]
380
- next if row[:Key_name] == 'PRIMARY' # skip the primary key
381
- current_index = row[:Key_name]
382
-
383
- mysql_index_type = row[:Index_type].downcase.to_sym
384
- index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
385
- index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
386
- indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], {}, nil, nil, index_type, index_using, row[:Index_comment].presence)
387
- end
388
-
389
- indexes.last.columns << row[:Column_name]
390
- indexes.last.lengths.merge!(row[:Column_name] => row[:Sub_part].to_i) if row[:Sub_part]
391
- end
392
- end
393
-
394
- indexes
395
- end
396
-
397
- # Returns an array of +Column+ objects for the table specified by +table_name+.
398
- def columns(table_name) # :nodoc:
399
- table_name = table_name.to_s
400
- column_definitions(table_name).map do |field|
401
- type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
402
- if type_metadata.type == :datetime && field[:Default] == "CURRENT_TIMESTAMP"
403
- default, default_function = nil, field[:Default]
404
- else
405
- default, default_function = field[:Default], nil
406
- end
407
- new_column(field[:Field], default, type_metadata, field[:Null] == "YES", table_name, default_function, field[:Collation], comment: field[:Comment].presence)
408
- end
284
+ show_variable "collation_database"
409
285
  end
410
286
 
411
287
  def table_comment(table_name) # :nodoc:
412
- schema, name = extract_schema_qualified_name(table_name)
288
+ scope = quoted_scope(table_name)
413
289
 
414
- select_value(<<-SQL.strip_heredoc, 'SCHEMA')
290
+ query_value(<<~SQL, "SCHEMA").presence
415
291
  SELECT table_comment
416
292
  FROM information_schema.tables
417
- WHERE table_schema = #{schema}
418
- AND table_name = #{name}
293
+ WHERE table_schema = #{scope[:schema]}
294
+ AND table_name = #{scope[:name]}
419
295
  SQL
420
296
  end
421
297
 
422
- def create_table(table_name, **options) #:nodoc:
423
- super(table_name, options: 'ENGINE=InnoDB', **options)
424
- end
425
-
426
- def bulk_change_table(table_name, operations) #:nodoc:
427
- sqls = operations.flat_map do |command, args|
428
- table, arguments = args.shift, args
429
- method = :"#{command}_sql"
430
-
431
- if respond_to?(method, true)
432
- send(method, table, *arguments)
433
- else
434
- raise "Unknown method called : #{method}(#{arguments.inspect})"
435
- end
436
- end.join(", ")
437
-
438
- execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
298
+ def change_table_comment(table_name, comment_or_changes) # :nodoc:
299
+ comment = extract_new_comment_value(comment_or_changes)
300
+ comment = "" if comment.nil?
301
+ execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
439
302
  end
440
303
 
441
304
  # Renames a table.
@@ -478,32 +341,34 @@ module ActiveRecord
478
341
 
479
342
  def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
480
343
  default = extract_new_default_value(default_or_changes)
481
- column = column_for(table_name, column_name)
482
- change_column table_name, column_name, column.sql_type, :default => default
344
+ change_column table_name, column_name, nil, default: default
483
345
  end
484
346
 
485
347
  def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
486
- column = column_for(table_name, column_name)
487
-
488
348
  unless null || default.nil?
489
349
  execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
490
350
  end
491
351
 
492
- change_column table_name, column_name, column.sql_type, :null => null
352
+ change_column table_name, column_name, nil, null: null
353
+ end
354
+
355
+ def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
356
+ comment = extract_new_comment_value(comment_or_changes)
357
+ change_column table_name, column_name, nil, comment: comment
493
358
  end
494
359
 
495
360
  def change_column(table_name, column_name, type, options = {}) #:nodoc:
496
- execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")
361
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
497
362
  end
498
363
 
499
364
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
500
- execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
365
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_for_alter(table_name, column_name, new_column_name)}")
501
366
  rename_column_indexes(table_name, column_name, new_column_name)
502
367
  end
503
368
 
504
369
  def add_index(table_name, column_name, options = {}) #:nodoc:
505
370
  index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
506
- sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
371
+ sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
507
372
  execute add_sql_comment!(sql, comment)
508
373
  end
509
374
 
@@ -515,35 +380,36 @@ module ActiveRecord
515
380
  def foreign_keys(table_name)
516
381
  raise ArgumentError unless table_name.present?
517
382
 
518
- schema, name = extract_schema_qualified_name(table_name)
383
+ scope = quoted_scope(table_name)
519
384
 
520
- fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
385
+ fk_info = exec_query(<<~SQL, "SCHEMA")
521
386
  SELECT fk.referenced_table_name AS 'to_table',
522
387
  fk.referenced_column_name AS 'primary_key',
523
388
  fk.column_name AS 'column',
524
389
  fk.constraint_name AS 'name',
525
390
  rc.update_rule AS 'on_update',
526
391
  rc.delete_rule AS 'on_delete'
527
- FROM information_schema.key_column_usage fk
528
- JOIN information_schema.referential_constraints rc
392
+ FROM information_schema.referential_constraints rc
393
+ JOIN information_schema.key_column_usage fk
529
394
  USING (constraint_schema, constraint_name)
530
395
  WHERE fk.referenced_column_name IS NOT NULL
531
- AND fk.table_schema = #{schema}
532
- AND fk.table_name = #{name}
533
- AND rc.table_name = #{name}
396
+ AND fk.table_schema = #{scope[:schema]}
397
+ AND fk.table_name = #{scope[:name]}
398
+ AND rc.constraint_schema = #{scope[:schema]}
399
+ AND rc.table_name = #{scope[:name]}
534
400
  SQL
535
401
 
536
402
  fk_info.map do |row|
537
403
  options = {
538
- column: row['column'],
539
- name: row['name'],
540
- primary_key: row['primary_key']
404
+ column: row["column"],
405
+ name: row["name"],
406
+ primary_key: row["primary_key"]
541
407
  }
542
408
 
543
- options[:on_update] = extract_foreign_key_action(row['on_update'])
544
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
409
+ options[:on_update] = extract_foreign_key_action(row["on_update"])
410
+ options[:on_delete] = extract_foreign_key_action(row["on_delete"])
545
411
 
546
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
412
+ ForeignKeyDefinition.new(table_name, row["to_table"], options)
547
413
  end
548
414
  end
549
415
 
@@ -553,7 +419,7 @@ module ActiveRecord
553
419
  create_table_info = create_table_info(table_name)
554
420
 
555
421
  # strip create_definitions and partition_options
556
- raw_table_options = create_table_info.sub(/\A.*\n\) /m, '').sub(/\n\/\*!.*\*\/\n\z/m, '').strip
422
+ raw_table_options = create_table_info.sub(/\A.*\n\) /m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
557
423
 
558
424
  # strip AUTO_INCREMENT
559
425
  raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
@@ -561,39 +427,16 @@ module ActiveRecord
561
427
  table_options[:options] = raw_table_options
562
428
 
563
429
  # strip COMMENT
564
- if raw_table_options.sub!(/ COMMENT='.+'/, '')
430
+ if raw_table_options.sub!(/ COMMENT='.+'/, "")
565
431
  table_options[:comment] = table_comment(table_name)
566
432
  end
567
433
 
568
434
  table_options
569
435
  end
570
436
 
571
- # Maps logical Rails types to MySQL-specific data types.
572
- def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
573
- sql = case type.to_s
574
- when 'integer'
575
- integer_to_sql(limit)
576
- when 'text'
577
- text_to_sql(limit)
578
- when 'blob'
579
- binary_to_sql(limit)
580
- when 'binary'
581
- if (0..0xfff) === limit
582
- "varbinary(#{limit})"
583
- else
584
- binary_to_sql(limit)
585
- end
586
- else
587
- super(type, limit, precision, scale)
588
- end
589
-
590
- sql << ' unsigned' if unsigned && type != :primary_key
591
- sql
592
- end
593
-
594
437
  # SHOW VARIABLES LIKE 'name'
595
438
  def show_variable(name)
596
- select_value("SELECT @@#{name}", 'SCHEMA')
439
+ query_value("SELECT @@#{name}", "SCHEMA")
597
440
  rescue ActiveRecord::StatementInvalid
598
441
  nil
599
442
  end
@@ -601,21 +444,38 @@ module ActiveRecord
601
444
  def primary_keys(table_name) # :nodoc:
602
445
  raise ArgumentError unless table_name.present?
603
446
 
604
- schema, name = extract_schema_qualified_name(table_name)
447
+ scope = quoted_scope(table_name)
605
448
 
606
- select_values(<<-SQL.strip_heredoc, 'SCHEMA')
449
+ query_values(<<~SQL, "SCHEMA")
607
450
  SELECT column_name
608
- FROM information_schema.key_column_usage
609
- WHERE constraint_name = 'PRIMARY'
610
- AND table_schema = #{schema}
611
- AND table_name = #{name}
612
- ORDER BY ordinal_position
451
+ FROM information_schema.statistics
452
+ WHERE index_name = 'PRIMARY'
453
+ AND table_schema = #{scope[:schema]}
454
+ AND table_name = #{scope[:name]}
455
+ ORDER BY seq_in_index
613
456
  SQL
614
457
  end
615
458
 
616
- def case_sensitive_comparison(table, attribute, column, value)
617
- if !value.nil? && column.collation && !column.case_sensitive?
618
- table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
459
+ def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
460
+ column = column_for_attribute(attribute)
461
+
462
+ if column.collation && !column.case_sensitive? && !value.nil?
463
+ ActiveSupport::Deprecation.warn(<<~MSG.squish)
464
+ Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
465
+ To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
466
+ pass `case_sensitive: true` option explicitly to the uniqueness validator.
467
+ MSG
468
+ attribute.eq(Arel::Nodes::Bin.new(value))
469
+ else
470
+ super
471
+ end
472
+ end
473
+
474
+ def case_sensitive_comparison(attribute, value) # :nodoc:
475
+ column = column_for_attribute(attribute)
476
+
477
+ if column.collation && !column.case_sensitive?
478
+ attribute.eq(Arel::Nodes::Bin.new(value))
619
479
  else
620
480
  super
621
481
  end
@@ -635,342 +495,336 @@ module ActiveRecord
635
495
  # Convert Arel node to string
636
496
  s = s.to_sql unless s.is_a?(String)
637
497
  # Remove any ASC/DESC modifiers
638
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
498
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
639
499
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
640
500
 
641
- [super, *order_columns].join(', ')
501
+ (order_columns << super).join(", ")
642
502
  end
643
503
 
644
504
  def strict_mode?
645
505
  self.class.type_cast_config_to_boolean(@config.fetch(:strict, true))
646
506
  end
647
507
 
648
- def valid_type?(type)
649
- !native_database_types[type].nil?
508
+ def default_index_type?(index) # :nodoc:
509
+ index.using == :btree || super
650
510
  end
651
511
 
652
- protected
512
+ def build_insert_sql(insert) # :nodoc:
513
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
653
514
 
654
- def initialize_type_map(m) # :nodoc:
655
- super
656
-
657
- register_class_with_limit m, %r(char)i, MysqlString
658
-
659
- m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
660
- m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
661
- m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
662
- m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
663
- m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
664
- m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
665
- m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
666
- m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
667
- m.register_type %r(^float)i, Type::Float.new(limit: 24)
668
- m.register_type %r(^double)i, Type::Float.new(limit: 53)
669
- m.register_type %r(^json)i, MysqlJson.new
670
-
671
- register_integer_type m, %r(^bigint)i, limit: 8
672
- register_integer_type m, %r(^int)i, limit: 4
673
- register_integer_type m, %r(^mediumint)i, limit: 3
674
- register_integer_type m, %r(^smallint)i, limit: 2
675
- register_integer_type m, %r(^tinyint)i, limit: 1
676
-
677
- m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
678
- m.alias_type %r(year)i, 'integer'
679
- m.alias_type %r(bit)i, 'binary'
680
-
681
- m.register_type(%r(enum)i) do |sql_type|
682
- limit = sql_type[/^enum\((.+)\)/i, 1]
683
- .split(',').map{|enum| enum.strip.length - 2}.max
684
- MysqlString.new(limit: limit)
515
+ if insert.skip_duplicates?
516
+ no_op_column = quote_column_name(insert.keys.first)
517
+ sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
518
+ elsif insert.update_duplicates?
519
+ sql << " ON DUPLICATE KEY UPDATE "
520
+ sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
685
521
  end
686
522
 
687
- m.register_type(%r(^set)i) do |sql_type|
688
- limit = sql_type[/^set\((.+)\)/i, 1]
689
- .split(',').map{|set| set.strip.length - 1}.sum - 1
690
- MysqlString.new(limit: limit)
691
- end
523
+ sql
692
524
  end
693
525
 
694
- def register_integer_type(mapping, key, options) # :nodoc:
695
- mapping.register_type(key) do |sql_type|
696
- if /\bunsigned\b/ === sql_type
697
- Type::UnsignedInteger.new(options)
698
- else
699
- Type::Integer.new(options)
700
- end
526
+ def check_version # :nodoc:
527
+ if database_version < "5.5.8"
528
+ raise "Your version of MySQL (#{database_version}) is too old. Active Record supports MySQL >= 5.5.8."
701
529
  end
702
530
  end
703
531
 
704
- def extract_precision(sql_type)
705
- if /time/ === sql_type
706
- super || 0
707
- else
532
+ private
533
+
534
+ def initialize_type_map(m = type_map)
708
535
  super
709
- end
710
- end
711
536
 
712
- def fetch_type_metadata(sql_type, extra = "")
713
- MySQL::TypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?)
714
- end
537
+ register_class_with_limit m, %r(char)i, MysqlString
538
+
539
+ m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
540
+ m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
541
+ m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
542
+ m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
543
+ m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
544
+ m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
545
+ m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
546
+ m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
547
+ m.register_type %r(^float)i, Type::Float.new(limit: 24)
548
+ m.register_type %r(^double)i, Type::Float.new(limit: 53)
549
+
550
+ register_integer_type m, %r(^bigint)i, limit: 8
551
+ register_integer_type m, %r(^int)i, limit: 4
552
+ register_integer_type m, %r(^mediumint)i, limit: 3
553
+ register_integer_type m, %r(^smallint)i, limit: 2
554
+ register_integer_type m, %r(^tinyint)i, limit: 1
555
+
556
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
557
+ m.alias_type %r(year)i, "integer"
558
+ m.alias_type %r(bit)i, "binary"
559
+
560
+ m.register_type(%r(enum)i) do |sql_type|
561
+ limit = sql_type[/^enum\s*\((.+)\)/i, 1]
562
+ .split(",").map { |enum| enum.strip.length - 2 }.max
563
+ MysqlString.new(limit: limit)
564
+ end
715
565
 
716
- def add_index_length(quoted_columns, **options)
717
- if length = options[:length]
718
- case length
719
- when Hash
720
- length = length.symbolize_keys
721
- quoted_columns.each { |name, column| column << "(#{length[name]})" if length[name].present? }
722
- when Integer
723
- quoted_columns.each { |name, column| column << "(#{length})" }
566
+ m.register_type(%r(^set)i) do |sql_type|
567
+ limit = sql_type[/^set\s*\((.+)\)/i, 1]
568
+ .split(",").map { |set| set.strip.length - 1 }.sum - 1
569
+ MysqlString.new(limit: limit)
724
570
  end
725
571
  end
726
572
 
727
- quoted_columns
728
- end
729
-
730
- def add_options_for_index_columns(quoted_columns, **options)
731
- quoted_columns = add_index_length(quoted_columns, options)
732
- super
733
- end
734
-
735
- def translate_exception(exception, message)
736
- case error_number(exception)
737
- when 1062
738
- RecordNotUnique.new(message)
739
- when 1452
740
- InvalidForeignKey.new(message)
741
- when 1406
742
- ValueTooLong.new(message)
743
- else
744
- super
573
+ def register_integer_type(mapping, key, options)
574
+ mapping.register_type(key) do |sql_type|
575
+ if /\bunsigned\b/.match?(sql_type)
576
+ Type::UnsignedInteger.new(options)
577
+ else
578
+ Type::Integer.new(options)
579
+ end
580
+ end
745
581
  end
746
- end
747
-
748
- def add_column_sql(table_name, column_name, type, options = {})
749
- td = create_table_definition(table_name)
750
- cd = td.new_column_definition(column_name, type, options)
751
- schema_creation.accept(AddColumnDefinition.new(cd))
752
- end
753
-
754
- def change_column_sql(table_name, column_name, type, options = {})
755
- column = column_for(table_name, column_name)
756
582
 
757
- unless options_include_default?(options)
758
- options[:default] = column.default
583
+ def extract_precision(sql_type)
584
+ if /\A(?:date)?time(?:stamp)?\b/.match?(sql_type)
585
+ super || 0
586
+ else
587
+ super
588
+ end
759
589
  end
760
590
 
761
- unless options.has_key?(:null)
762
- options[:null] = column.null
591
+ # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
592
+ ER_FILSORT_ABORT = 1028
593
+ ER_DUP_ENTRY = 1062
594
+ ER_NOT_NULL_VIOLATION = 1048
595
+ ER_NO_REFERENCED_ROW = 1216
596
+ ER_ROW_IS_REFERENCED = 1217
597
+ ER_DO_NOT_HAVE_DEFAULT = 1364
598
+ ER_ROW_IS_REFERENCED_2 = 1451
599
+ ER_NO_REFERENCED_ROW_2 = 1452
600
+ ER_DATA_TOO_LONG = 1406
601
+ ER_OUT_OF_RANGE = 1264
602
+ ER_LOCK_DEADLOCK = 1213
603
+ ER_CANNOT_ADD_FOREIGN = 1215
604
+ ER_CANNOT_CREATE_TABLE = 1005
605
+ ER_LOCK_WAIT_TIMEOUT = 1205
606
+ ER_QUERY_INTERRUPTED = 1317
607
+ ER_QUERY_TIMEOUT = 3024
608
+ ER_FK_INCOMPATIBLE_COLUMNS = 3780
609
+
610
+ def translate_exception(exception, message:, sql:, binds:)
611
+ case error_number(exception)
612
+ when ER_DUP_ENTRY
613
+ RecordNotUnique.new(message, sql: sql, binds: binds)
614
+ when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
615
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
616
+ when ER_CANNOT_ADD_FOREIGN, ER_FK_INCOMPATIBLE_COLUMNS
617
+ mismatched_foreign_key(message, sql: sql, binds: binds)
618
+ when ER_CANNOT_CREATE_TABLE
619
+ if message.include?("errno: 150")
620
+ mismatched_foreign_key(message, sql: sql, binds: binds)
621
+ else
622
+ super
623
+ end
624
+ when ER_DATA_TOO_LONG
625
+ ValueTooLong.new(message, sql: sql, binds: binds)
626
+ when ER_OUT_OF_RANGE
627
+ RangeError.new(message, sql: sql, binds: binds)
628
+ when ER_NOT_NULL_VIOLATION, ER_DO_NOT_HAVE_DEFAULT
629
+ NotNullViolation.new(message, sql: sql, binds: binds)
630
+ when ER_LOCK_DEADLOCK
631
+ Deadlocked.new(message, sql: sql, binds: binds)
632
+ when ER_LOCK_WAIT_TIMEOUT
633
+ LockWaitTimeout.new(message, sql: sql, binds: binds)
634
+ when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
635
+ StatementTimeout.new(message, sql: sql, binds: binds)
636
+ when ER_QUERY_INTERRUPTED
637
+ QueryCanceled.new(message, sql: sql, binds: binds)
638
+ else
639
+ super
640
+ end
763
641
  end
764
642
 
765
- td = create_table_definition(table_name)
766
- cd = td.new_column_definition(column.name, type, options)
767
- schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
768
- end
643
+ def change_column_for_alter(table_name, column_name, type, options = {})
644
+ column = column_for(table_name, column_name)
645
+ type ||= column.sql_type
769
646
 
770
- def rename_column_sql(table_name, column_name, new_column_name)
771
- column = column_for(table_name, column_name)
772
- options = {
773
- default: column.default,
774
- null: column.null,
775
- auto_increment: column.auto_increment?
776
- }
647
+ unless options.key?(:default)
648
+ options[:default] = column.default
649
+ end
777
650
 
778
- current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
779
- td = create_table_definition(table_name)
780
- cd = td.new_column_definition(new_column_name, current_type, options)
781
- schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
782
- end
651
+ unless options.key?(:null)
652
+ options[:null] = column.null
653
+ end
783
654
 
784
- def remove_column_sql(table_name, column_name, type = nil, options = {})
785
- "DROP #{quote_column_name(column_name)}"
786
- end
655
+ unless options.key?(:comment)
656
+ options[:comment] = column.comment
657
+ end
787
658
 
788
- def remove_columns_sql(table_name, *column_names)
789
- column_names.map {|column_name| remove_column_sql(table_name, column_name) }
790
- end
659
+ td = create_table_definition(table_name)
660
+ cd = td.new_column_definition(column.name, type, options)
661
+ schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
662
+ end
791
663
 
792
- def add_index_sql(table_name, column_name, options = {})
793
- index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
794
- index_algorithm[0, 0] = ", " if index_algorithm.present?
795
- "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
796
- end
664
+ def rename_column_for_alter(table_name, column_name, new_column_name)
665
+ column = column_for(table_name, column_name)
666
+ options = {
667
+ default: column.default,
668
+ null: column.null,
669
+ auto_increment: column.auto_increment?
670
+ }
797
671
 
798
- def remove_index_sql(table_name, options = {})
799
- index_name = index_name_for_remove(table_name, options)
800
- "DROP INDEX #{index_name}"
801
- end
672
+ current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
673
+ td = create_table_definition(table_name)
674
+ cd = td.new_column_definition(new_column_name, current_type, options)
675
+ schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
676
+ end
802
677
 
803
- def add_timestamps_sql(table_name, options = {})
804
- [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
805
- end
678
+ def add_index_for_alter(table_name, column_name, options = {})
679
+ index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
680
+ index_algorithm[0, 0] = ", " if index_algorithm.present?
681
+ "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
682
+ end
806
683
 
807
- def remove_timestamps_sql(table_name, options = {})
808
- [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
809
- end
684
+ def remove_index_for_alter(table_name, options = {})
685
+ index_name = index_name_for_remove(table_name, options)
686
+ "DROP INDEX #{quote_column_name(index_name)}"
687
+ end
810
688
 
811
- private
689
+ def add_timestamps_for_alter(table_name, options = {})
690
+ options[:null] = false if options[:null].nil?
812
691
 
813
- # MySQL is too stupid to create a temporary table for use subquery, so we have
814
- # to give it some prompting in the form of a subsubquery. Ugh!
815
- def subquery_for(key, select)
816
- subsubselect = select.clone
817
- subsubselect.projections = [key]
692
+ if !options.key?(:precision) && supports_datetime_with_precision?
693
+ options[:precision] = 6
694
+ end
818
695
 
819
- # Materialize subquery by adding distinct
820
- # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
821
- subsubselect.distinct unless select.limit || select.offset || select.orders.any?
696
+ [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
697
+ end
822
698
 
823
- subselect = Arel::SelectManager.new(select.engine)
824
- subselect.project Arel.sql(key.name)
825
- subselect.from subsubselect.as('__active_record_temp')
826
- end
699
+ def remove_timestamps_for_alter(table_name, options = {})
700
+ [remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
701
+ end
827
702
 
828
- def supports_rename_index?
829
- mariadb? ? false : version >= '5.7.6'
830
- end
703
+ def supports_rename_index?
704
+ mariadb? ? false : database_version >= "5.7.6"
705
+ end
831
706
 
832
- def configure_connection
833
- variables = @config.fetch(:variables, {}).stringify_keys
707
+ def configure_connection
708
+ variables = @config.fetch(:variables, {}).stringify_keys
834
709
 
835
- # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
836
- variables['sql_auto_is_null'] = 0
710
+ # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
711
+ variables["sql_auto_is_null"] = 0
837
712
 
838
- # Increase timeout so the server doesn't disconnect us.
839
- wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
840
- wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
841
- variables["wait_timeout"] = wait_timeout
713
+ # Increase timeout so the server doesn't disconnect us.
714
+ wait_timeout = self.class.type_cast_config_to_integer(@config[:wait_timeout])
715
+ wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
716
+ variables["wait_timeout"] = wait_timeout
842
717
 
843
- defaults = [':default', :default].to_set
718
+ defaults = [":default", :default].to_set
844
719
 
845
- # Make MySQL reject illegal values rather than truncating or blanking them, see
846
- # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
847
- # If the user has provided another value for sql_mode, don't replace it.
848
- if sql_mode = variables.delete('sql_mode')
849
- sql_mode = quote(sql_mode)
850
- elsif !defaults.include?(strict_mode?)
851
- if strict_mode?
852
- sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
853
- else
854
- sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
855
- sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
856
- sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
720
+ # Make MySQL reject illegal values rather than truncating or blanking them, see
721
+ # https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
722
+ # If the user has provided another value for sql_mode, don't replace it.
723
+ if sql_mode = variables.delete("sql_mode")
724
+ sql_mode = quote(sql_mode)
725
+ elsif !defaults.include?(strict_mode?)
726
+ if strict_mode?
727
+ sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
728
+ else
729
+ sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
730
+ sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
731
+ sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
732
+ end
733
+ sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
857
734
  end
858
- sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
859
- end
860
- sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
861
-
862
- # NAMES does not have an equals sign, see
863
- # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430
864
- # (trailing comma because variable_assignments will always have content)
865
- if @config[:encoding]
866
- encoding = "NAMES #{@config[:encoding]}"
867
- encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
868
- encoding << ", "
869
- end
870
-
871
- # Gather up all of the SET variables...
872
- variable_assignments = variables.map do |k, v|
873
- if defaults.include?(v)
874
- "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
875
- elsif !v.nil?
876
- "@@SESSION.#{k} = #{quote(v)}"
735
+ sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
736
+
737
+ # NAMES does not have an equals sign, see
738
+ # https://dev.mysql.com/doc/refman/5.7/en/set-names.html
739
+ # (trailing comma because variable_assignments will always have content)
740
+ if @config[:encoding]
741
+ encoding = +"NAMES #{@config[:encoding]}"
742
+ encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
743
+ encoding << ", "
877
744
  end
878
- # or else nil; compact to clear nils out
879
- end.compact.join(', ')
880
745
 
881
- # ...and send them all in one query
882
- @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
883
- end
746
+ # Gather up all of the SET variables...
747
+ variable_assignments = variables.map do |k, v|
748
+ if defaults.include?(v)
749
+ "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
750
+ elsif !v.nil?
751
+ "@@SESSION.#{k} = #{quote(v)}"
752
+ end
753
+ # or else nil; compact to clear nils out
754
+ end.compact.join(", ")
884
755
 
885
- def column_definitions(table_name) # :nodoc:
886
- execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
887
- each_hash(result)
756
+ # ...and send them all in one query
757
+ execute "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
888
758
  end
889
- end
890
759
 
891
- def extract_foreign_key_action(specifier) # :nodoc:
892
- case specifier
893
- when 'CASCADE'; :cascade
894
- when 'SET NULL'; :nullify
760
+ def column_definitions(table_name) # :nodoc:
761
+ execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
762
+ each_hash(result)
763
+ end
895
764
  end
896
- end
897
-
898
- def create_table_info(table_name) # :nodoc:
899
- select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
900
- end
901
-
902
- def create_table_definition(*args) # :nodoc:
903
- MySQL::TableDefinition.new(*args)
904
- end
905
765
 
906
- def extract_schema_qualified_name(string) # :nodoc:
907
- schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/).map { |s| quote(s) }
908
- schema, name = "DATABASE()", schema unless name
909
- [schema, name]
910
- end
911
-
912
- def integer_to_sql(limit) # :nodoc:
913
- case limit
914
- when 1; 'tinyint'
915
- when 2; 'smallint'
916
- when 3; 'mediumint'
917
- when nil, 4; 'int'
918
- when 5..8; 'bigint'
919
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
766
+ def create_table_info(table_name) # :nodoc:
767
+ exec_query("SHOW CREATE TABLE #{quote_table_name(table_name)}", "SCHEMA").first["Create Table"]
920
768
  end
921
- end
922
769
 
923
- def text_to_sql(limit) # :nodoc:
924
- case limit
925
- when 0..0xff; 'tinytext'
926
- when nil, 0x100..0xffff; 'text'
927
- when 0x10000..0xffffff; 'mediumtext'
928
- when 0x1000000..0xffffffff; 'longtext'
929
- else raise(ActiveRecordError, "No text type has byte length #{limit}")
770
+ def arel_visitor
771
+ Arel::Visitors::MySQL.new(self)
930
772
  end
931
- end
932
773
 
933
- def binary_to_sql(limit) # :nodoc:
934
- case limit
935
- when 0..0xff; 'tinyblob'
936
- when nil, 0x100..0xffff; 'blob'
937
- when 0x10000..0xffffff; 'mediumblob'
938
- when 0x1000000..0xffffffff; 'longblob'
939
- else raise(ActiveRecordError, "No binary type has byte length #{limit}")
774
+ def build_statement_pool
775
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
940
776
  end
941
- end
942
777
 
943
- class MysqlJson < Type::Internal::AbstractJson # :nodoc:
944
- def changed_in_place?(raw_old_value, new_value)
945
- # Normalization is required because MySQL JSON data format includes
946
- # the space between the elements.
947
- super(serialize(deserialize(raw_old_value)), new_value)
948
- end
949
- end
778
+ def mismatched_foreign_key(message, sql:, binds:)
779
+ match = %r/
780
+ (?:CREATE|ALTER)\s+TABLE\s*(?:`?\w+`?\.)?`?(?<table>\w+)`?.+?
781
+ FOREIGN\s+KEY\s*\(`?(?<foreign_key>\w+)`?\)\s*
782
+ REFERENCES\s*(`?(?<target_table>\w+)`?)\s*\(`?(?<primary_key>\w+)`?\)
783
+ /xmi.match(sql)
784
+
785
+ options = {
786
+ message: message,
787
+ sql: sql,
788
+ binds: binds,
789
+ }
950
790
 
951
- class MysqlString < Type::String # :nodoc:
952
- def serialize(value)
953
- case value
954
- when true then MySQL::Quoting::QUOTED_TRUE
955
- when false then MySQL::Quoting::QUOTED_FALSE
956
- else super
791
+ if match
792
+ options[:table] = match[:table]
793
+ options[:foreign_key] = match[:foreign_key]
794
+ options[:target_table] = match[:target_table]
795
+ options[:primary_key] = match[:primary_key]
796
+ options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
957
797
  end
798
+
799
+ MismatchedForeignKey.new(options)
958
800
  end
959
801
 
960
- private
802
+ def version_string(full_version_string)
803
+ full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
804
+ end
961
805
 
962
- def cast_value(value)
963
- case value
964
- when true then MySQL::Quoting::QUOTED_TRUE
965
- when false then MySQL::Quoting::QUOTED_FALSE
966
- else super
806
+ class MysqlString < Type::String # :nodoc:
807
+ def serialize(value)
808
+ case value
809
+ when true then "1"
810
+ when false then "0"
811
+ else super
812
+ end
967
813
  end
814
+
815
+ private
816
+
817
+ def cast_value(value)
818
+ case value
819
+ when true then "1"
820
+ when false then "0"
821
+ else super
822
+ end
823
+ end
968
824
  end
969
- end
970
825
 
971
- ActiveRecord::Type.register(:json, MysqlJson, adapter: :mysql2)
972
- ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
973
- ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
826
+ ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
827
+ ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
974
828
  end
975
829
  end
976
830
  end