activerecord 5.0.7.2 → 6.0.6.1

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

Potentially problematic release.


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

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