activerecord 6.0.0 → 6.1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1413 -614
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +38 -13
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +77 -42
  28. data/lib/active_record/associations/preloader/association.rb +49 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +13 -8
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +120 -13
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +63 -44
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +24 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -66
  104. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +40 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +219 -81
  114. data/lib/active_record/core.rb +283 -71
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +125 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +3 -3
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -10
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +18 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +75 -21
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +120 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +55 -17
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +346 -181
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -82
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +9 -4
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +87 -20
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +26 -73
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +15 -12
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +31 -27
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -45,7 +45,6 @@ module ActiveRecord
45
45
 
46
46
  class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
47
47
  private
48
-
49
48
  def dealloc(stmt)
50
49
  stmt.close
51
50
  end
@@ -93,6 +92,14 @@ module ActiveRecord
93
92
  true
94
93
  end
95
94
 
95
+ def supports_check_constraints?
96
+ if mariadb?
97
+ database_version >= "10.2.1"
98
+ else
99
+ database_version >= "8.0.16"
100
+ end
101
+ end
102
+
96
103
  def supports_views?
97
104
  true
98
105
  end
@@ -105,11 +112,19 @@ module ActiveRecord
105
112
  mariadb? || database_version >= "5.7.5"
106
113
  end
107
114
 
108
- # See https://dev.mysql.com/doc/refman/8.0/en/optimizer-hints.html for more details.
115
+ # See https://dev.mysql.com/doc/refman/en/optimizer-hints.html for more details.
109
116
  def supports_optimizer_hints?
110
117
  !mariadb? && database_version >= "5.7.7"
111
118
  end
112
119
 
120
+ def supports_common_table_expressions?
121
+ if mariadb?
122
+ database_version >= "10.2.1"
123
+ else
124
+ database_version >= "8.0.1"
125
+ end
126
+ end
127
+
113
128
  def supports_advisory_locks?
114
129
  true
115
130
  end
@@ -135,7 +150,12 @@ module ActiveRecord
135
150
  end
136
151
 
137
152
  def index_algorithms
138
- { default: +"ALGORITHM = DEFAULT", copy: +"ALGORITHM = COPY", inplace: +"ALGORITHM = INPLACE" }
153
+ {
154
+ default: "ALGORITHM = DEFAULT",
155
+ copy: "ALGORITHM = COPY",
156
+ inplace: "ALGORITHM = INPLACE",
157
+ instant: "ALGORITHM = INSTANT",
158
+ }
139
159
  end
140
160
 
141
161
  # HELPER METHODS ===========================================
@@ -176,18 +196,10 @@ module ActiveRecord
176
196
  # DATABASE STATEMENTS ======================================
177
197
  #++
178
198
 
179
- def explain(arel, binds = [])
180
- sql = "EXPLAIN #{to_sql(arel, binds)}"
181
- start = Concurrent.monotonic_time
182
- result = exec_query(sql, "EXPLAIN", binds)
183
- elapsed = Concurrent.monotonic_time - start
184
-
185
- MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
186
- end
187
-
188
199
  # Executes the SQL statement in the context of this connection.
189
200
  def execute(sql, name = nil)
190
201
  materialize_transactions
202
+ mark_transaction_written_if_write(sql)
191
203
 
192
204
  log(sql, name) do
193
205
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
@@ -204,7 +216,7 @@ module ActiveRecord
204
216
  end
205
217
 
206
218
  def begin_db_transaction
207
- execute "BEGIN"
219
+ execute("BEGIN", "TRANSACTION")
208
220
  end
209
221
 
210
222
  def begin_isolated_db_transaction(isolation)
@@ -213,11 +225,11 @@ module ActiveRecord
213
225
  end
214
226
 
215
227
  def commit_db_transaction #:nodoc:
216
- execute "COMMIT"
228
+ execute("COMMIT", "TRANSACTION")
217
229
  end
218
230
 
219
231
  def exec_rollback_db_transaction #:nodoc:
220
- execute "ROLLBACK"
232
+ execute("ROLLBACK", "TRANSACTION")
221
233
  end
222
234
 
223
235
  def empty_insert_statement_value(primary_key = nil)
@@ -298,6 +310,8 @@ module ActiveRecord
298
310
  # Example:
299
311
  # rename_table('octopuses', 'octopi')
300
312
  def rename_table(table_name, new_name)
313
+ schema_cache.clear_data_source_cache!(table_name.to_s)
314
+ schema_cache.clear_data_source_cache!(new_name.to_s)
301
315
  execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
302
316
  rename_table_indexes(table_name, new_name)
303
317
  end
@@ -317,7 +331,8 @@ module ActiveRecord
317
331
  # Although this command ignores most +options+ and the block if one is given,
318
332
  # it can be helpful to provide these in a migration's +change+ method so it can be reverted.
319
333
  # In that case, +options+ and the block will be used by create_table.
320
- def drop_table(table_name, options = {})
334
+ def drop_table(table_name, **options)
335
+ schema_cache.clear_data_source_cache!(table_name.to_s)
321
336
  execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
322
337
  end
323
338
 
@@ -349,8 +364,8 @@ module ActiveRecord
349
364
  change_column table_name, column_name, nil, comment: comment
350
365
  end
351
366
 
352
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
353
- execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}")
367
+ def change_column(table_name, column_name, type, **options) #:nodoc:
368
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, **options)}")
354
369
  end
355
370
 
356
371
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
@@ -358,10 +373,13 @@ module ActiveRecord
358
373
  rename_column_indexes(table_name, column_name, new_column_name)
359
374
  end
360
375
 
361
- def add_index(table_name, column_name, options = {}) #:nodoc:
362
- index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
363
- sql = +"CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
364
- execute add_sql_comment!(sql, comment)
376
+ def add_index(table_name, column_name, **options) #:nodoc:
377
+ index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
378
+
379
+ return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
380
+
381
+ create_index = CreateIndexDefinition.new(index, algorithm)
382
+ execute schema_creation.accept(create_index)
365
383
  end
366
384
 
367
385
  def add_sql_comment!(sql, comment) # :nodoc:
@@ -405,24 +423,60 @@ module ActiveRecord
405
423
  end
406
424
  end
407
425
 
408
- def table_options(table_name) # :nodoc:
409
- table_options = {}
426
+ def check_constraints(table_name)
427
+ if supports_check_constraints?
428
+ scope = quoted_scope(table_name)
429
+
430
+ chk_info = exec_query(<<~SQL, "SCHEMA")
431
+ SELECT cc.constraint_name AS 'name',
432
+ cc.check_clause AS 'expression'
433
+ FROM information_schema.check_constraints cc
434
+ JOIN information_schema.table_constraints tc
435
+ USING (constraint_schema, constraint_name)
436
+ WHERE tc.table_schema = #{scope[:schema]}
437
+ AND tc.table_name = #{scope[:name]}
438
+ AND cc.constraint_schema = #{scope[:schema]}
439
+ SQL
440
+
441
+ chk_info.map do |row|
442
+ options = {
443
+ name: row["name"]
444
+ }
445
+ expression = row["expression"]
446
+ expression = expression[1..-2] unless mariadb? # remove parentheses added by mysql
447
+ CheckConstraintDefinition.new(table_name, expression, options)
448
+ end
449
+ else
450
+ raise NotImplementedError
451
+ end
452
+ end
410
453
 
454
+ def table_options(table_name) # :nodoc:
411
455
  create_table_info = create_table_info(table_name)
412
456
 
413
457
  # strip create_definitions and partition_options
414
- raw_table_options = create_table_info.sub(/\A.*\n\) /m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
458
+ # Be aware that `create_table_info` might not include any table options due to `NO_TABLE_OPTIONS` sql mode.
459
+ raw_table_options = create_table_info.sub(/\A.*\n\) ?/m, "").sub(/\n\/\*!.*\*\/\n\z/m, "").strip
460
+
461
+ return if raw_table_options.empty?
462
+
463
+ table_options = {}
464
+
465
+ if / DEFAULT CHARSET=(?<charset>\w+)(?: COLLATE=(?<collation>\w+))?/ =~ raw_table_options
466
+ raw_table_options = $` + $' # before part + after part
467
+ table_options[:charset] = charset
468
+ table_options[:collation] = collation if collation
469
+ end
415
470
 
416
471
  # strip AUTO_INCREMENT
417
472
  raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
418
473
 
419
- table_options[:options] = raw_table_options
420
-
421
474
  # strip COMMENT
422
475
  if raw_table_options.sub!(/ COMMENT='.+'/, "")
423
476
  table_options[:comment] = table_comment(table_name)
424
477
  end
425
478
 
479
+ table_options[:options] = raw_table_options unless raw_table_options == "ENGINE=InnoDB"
426
480
  table_options
427
481
  end
428
482
 
@@ -440,29 +494,14 @@ module ActiveRecord
440
494
 
441
495
  query_values(<<~SQL, "SCHEMA")
442
496
  SELECT column_name
443
- FROM information_schema.key_column_usage
444
- WHERE constraint_name = 'PRIMARY'
497
+ FROM information_schema.statistics
498
+ WHERE index_name = 'PRIMARY'
445
499
  AND table_schema = #{scope[:schema]}
446
500
  AND table_name = #{scope[:name]}
447
- ORDER BY ordinal_position
501
+ ORDER BY seq_in_index
448
502
  SQL
449
503
  end
450
504
 
451
- def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
452
- column = column_for_attribute(attribute)
453
-
454
- if column.collation && !column.case_sensitive? && !value.nil?
455
- ActiveSupport::Deprecation.warn(<<~MSG.squish)
456
- Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
457
- To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
458
- pass `case_sensitive: true` option explicitly to the uniqueness validator.
459
- MSG
460
- attribute.eq(Arel::Nodes::Bin.new(value))
461
- else
462
- super
463
- end
464
- end
465
-
466
505
  def case_sensitive_comparison(attribute, value) # :nodoc:
467
506
  column = column_for_attribute(attribute)
468
507
 
@@ -481,14 +520,14 @@ module ActiveRecord
481
520
  # In MySQL 5.7.5 and up, ONLY_FULL_GROUP_BY affects handling of queries that use
482
521
  # DISTINCT and ORDER BY. It requires the ORDER BY columns in the select list for
483
522
  # distinct queries, and requires that the ORDER BY include the distinct column.
484
- # See https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
523
+ # See https://dev.mysql.com/doc/refman/en/group-by-handling.html
485
524
  def columns_for_distinct(columns, orders) # :nodoc:
486
- order_columns = orders.reject(&:blank?).map { |s|
525
+ order_columns = orders.compact_blank.map { |s|
487
526
  # Convert Arel node to string
488
- s = s.to_sql unless s.is_a?(String)
527
+ s = visitor.compile(s) unless s.is_a?(String)
489
528
  # Remove any ASC/DESC modifiers
490
529
  s.gsub(/\s+(?:ASC|DESC)\b/i, "")
491
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
530
+ }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
492
531
 
493
532
  (order_columns << super).join(", ")
494
533
  end
@@ -509,6 +548,7 @@ module ActiveRecord
509
548
  sql << " ON DUPLICATE KEY UPDATE #{no_op_column}=#{no_op_column}"
510
549
  elsif insert.update_duplicates?
511
550
  sql << " ON DUPLICATE KEY UPDATE "
551
+ sql << insert.touch_model_timestamps_unless { |column| "#{column}<=>VALUES(#{column})" }
512
552
  sql << insert.updatable_columns.map { |column| "#{column}=VALUES(#{column})" }.join(",")
513
553
  end
514
554
 
@@ -522,11 +562,13 @@ module ActiveRecord
522
562
  end
523
563
 
524
564
  private
525
-
526
565
  def initialize_type_map(m = type_map)
527
566
  super
528
567
 
529
- register_class_with_limit m, %r(char)i, MysqlString
568
+ m.register_type(%r(char)i) do |sql_type|
569
+ limit = extract_limit(sql_type)
570
+ Type.lookup(:string, adapter: :mysql2, limit: limit)
571
+ end
530
572
 
531
573
  m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
532
574
  m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
@@ -546,28 +588,19 @@ module ActiveRecord
546
588
  register_integer_type m, %r(^tinyint)i, limit: 1
547
589
 
548
590
  m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
549
- m.alias_type %r(year)i, "integer"
550
- m.alias_type %r(bit)i, "binary"
591
+ m.alias_type %r(year)i, "integer"
592
+ m.alias_type %r(bit)i, "binary"
551
593
 
552
- m.register_type(%r(enum)i) do |sql_type|
553
- limit = sql_type[/^enum\s*\((.+)\)/i, 1]
554
- .split(",").map { |enum| enum.strip.length - 2 }.max
555
- MysqlString.new(limit: limit)
556
- end
557
-
558
- m.register_type(%r(^set)i) do |sql_type|
559
- limit = sql_type[/^set\s*\((.+)\)/i, 1]
560
- .split(",").map { |set| set.strip.length - 1 }.sum - 1
561
- MysqlString.new(limit: limit)
562
- end
594
+ m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
595
+ m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
563
596
  end
564
597
 
565
- def register_integer_type(mapping, key, options)
598
+ def register_integer_type(mapping, key, **options)
566
599
  mapping.register_type(key) do |sql_type|
567
600
  if /\bunsigned\b/.match?(sql_type)
568
- Type::UnsignedInteger.new(options)
601
+ Type::UnsignedInteger.new(**options)
569
602
  else
570
- Type::Integer.new(options)
603
+ Type::Integer.new(**options)
571
604
  end
572
605
  end
573
606
  end
@@ -580,7 +613,9 @@ module ActiveRecord
580
613
  end
581
614
  end
582
615
 
583
- # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html
616
+ # See https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html
617
+ ER_DB_CREATE_EXISTS = 1007
618
+ ER_FILSORT_ABORT = 1028
584
619
  ER_DUP_ENTRY = 1062
585
620
  ER_NOT_NULL_VIOLATION = 1048
586
621
  ER_NO_REFERENCED_ROW = 1216
@@ -600,6 +635,14 @@ module ActiveRecord
600
635
 
601
636
  def translate_exception(exception, message:, sql:, binds:)
602
637
  case error_number(exception)
638
+ when nil
639
+ if exception.message.match?(/MySQL client is not connected/i)
640
+ ConnectionNotEstablished.new(exception)
641
+ else
642
+ super
643
+ end
644
+ when ER_DB_CREATE_EXISTS
645
+ DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
603
646
  when ER_DUP_ENTRY
604
647
  RecordNotUnique.new(message, sql: sql, binds: binds)
605
648
  when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
@@ -622,7 +665,7 @@ module ActiveRecord
622
665
  Deadlocked.new(message, sql: sql, binds: binds)
623
666
  when ER_LOCK_WAIT_TIMEOUT
624
667
  LockWaitTimeout.new(message, sql: sql, binds: binds)
625
- when ER_QUERY_TIMEOUT
668
+ when ER_QUERY_TIMEOUT, ER_FILSORT_ABORT
626
669
  StatementTimeout.new(message, sql: sql, binds: binds)
627
670
  when ER_QUERY_INTERRUPTED
628
671
  QueryCanceled.new(message, sql: sql, binds: binds)
@@ -631,7 +674,7 @@ module ActiveRecord
631
674
  end
632
675
  end
633
676
 
634
- def change_column_for_alter(table_name, column_name, type, options = {})
677
+ def change_column_for_alter(table_name, column_name, type, **options)
635
678
  column = column_for(table_name, column_name)
636
679
  type ||= column.sql_type
637
680
 
@@ -648,51 +691,53 @@ module ActiveRecord
648
691
  end
649
692
 
650
693
  td = create_table_definition(table_name)
651
- cd = td.new_column_definition(column.name, type, options)
694
+ cd = td.new_column_definition(column.name, type, **options)
652
695
  schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
653
696
  end
654
697
 
655
698
  def rename_column_for_alter(table_name, column_name, new_column_name)
699
+ return rename_column_sql(table_name, column_name, new_column_name) if supports_rename_column?
700
+
656
701
  column = column_for(table_name, column_name)
657
702
  options = {
658
703
  default: column.default,
659
704
  null: column.null,
660
- auto_increment: column.auto_increment?
705
+ auto_increment: column.auto_increment?,
706
+ comment: column.comment
661
707
  }
662
708
 
663
709
  current_type = exec_query("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE #{quote(column_name)}", "SCHEMA").first["Type"]
664
710
  td = create_table_definition(table_name)
665
- cd = td.new_column_definition(new_column_name, current_type, options)
711
+ cd = td.new_column_definition(new_column_name, current_type, **options)
666
712
  schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
667
713
  end
668
714
 
669
- def add_index_for_alter(table_name, column_name, options = {})
670
- index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
671
- index_algorithm[0, 0] = ", " if index_algorithm.present?
672
- "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
715
+ def add_index_for_alter(table_name, column_name, **options)
716
+ index, algorithm, _ = add_index_options(table_name, column_name, **options)
717
+ algorithm = ", #{algorithm}" if algorithm
718
+
719
+ "ADD #{schema_creation.accept(index)}#{algorithm}"
673
720
  end
674
721
 
675
- def remove_index_for_alter(table_name, options = {})
676
- index_name = index_name_for_remove(table_name, options)
722
+ def remove_index_for_alter(table_name, column_name = nil, **options)
723
+ index_name = index_name_for_remove(table_name, column_name, options)
677
724
  "DROP INDEX #{quote_column_name(index_name)}"
678
725
  end
679
726
 
680
- def add_timestamps_for_alter(table_name, options = {})
681
- options[:null] = false if options[:null].nil?
682
-
683
- if !options.key?(:precision) && supports_datetime_with_precision?
684
- options[:precision] = 6
727
+ def supports_rename_index?
728
+ if mariadb?
729
+ database_version >= "10.5.2"
730
+ else
731
+ database_version >= "5.7.6"
685
732
  end
686
-
687
- [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
688
733
  end
689
734
 
690
- def remove_timestamps_for_alter(table_name, options = {})
691
- [remove_column_for_alter(table_name, :updated_at), remove_column_for_alter(table_name, :created_at)]
692
- end
693
-
694
- def supports_rename_index?
695
- mariadb? ? false : database_version >= "5.7.6"
735
+ def supports_rename_column?
736
+ if mariadb?
737
+ database_version >= "10.5.2"
738
+ else
739
+ database_version >= "8.0.3"
740
+ end
696
741
  end
697
742
 
698
743
  def configure_connection
@@ -709,7 +754,7 @@ module ActiveRecord
709
754
  defaults = [":default", :default].to_set
710
755
 
711
756
  # Make MySQL reject illegal values rather than truncating or blanking them, see
712
- # https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
757
+ # https://dev.mysql.com/doc/refman/en/sql-mode.html#sqlmode_strict_all_tables
713
758
  # If the user has provided another value for sql_mode, don't replace it.
714
759
  if sql_mode = variables.delete("sql_mode")
715
760
  sql_mode = quote(sql_mode)
@@ -726,7 +771,7 @@ module ActiveRecord
726
771
  sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
727
772
 
728
773
  # NAMES does not have an equals sign, see
729
- # https://dev.mysql.com/doc/refman/5.7/en/set-names.html
774
+ # https://dev.mysql.com/doc/refman/en/set-names.html
730
775
  # (trailing comma because variable_assignments will always have content)
731
776
  if @config[:encoding]
732
777
  encoding = +"NAMES #{@config[:encoding]}"
@@ -745,7 +790,7 @@ module ActiveRecord
745
790
  end.compact.join(", ")
746
791
 
747
792
  # ...and send them all in one query
748
- execute "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
793
+ execute("SET #{encoding} #{sql_mode_assignment} #{variable_assignments}", "SCHEMA")
749
794
  end
750
795
 
751
796
  def column_definitions(table_name) # :nodoc:
@@ -787,34 +832,23 @@ module ActiveRecord
787
832
  options[:primary_key_column] = column_for(match[:target_table], match[:primary_key])
788
833
  end
789
834
 
790
- MismatchedForeignKey.new(options)
835
+ MismatchedForeignKey.new(**options)
791
836
  end
792
837
 
793
838
  def version_string(full_version_string)
794
839
  full_version_string.match(/^(?:5\.5\.5-)?(\d+\.\d+\.\d+)/)[1]
795
840
  end
796
841
 
797
- class MysqlString < Type::String # :nodoc:
798
- def serialize(value)
799
- case value
800
- when true then "1"
801
- when false then "0"
802
- else super
803
- end
804
- end
805
-
806
- private
842
+ # Alias MysqlString to work Mashal.load(File.read("legacy_record.dump")).
843
+ # TODO: Remove the constant alias once Rails 6.1 has released.
844
+ MysqlString = Type::String # :nodoc:
807
845
 
808
- def cast_value(value)
809
- case value
810
- when true then "1"
811
- when false then "0"
812
- else super
813
- end
814
- end
846
+ ActiveRecord::Type.register(:immutable_string, adapter: :mysql2) do |_, **args|
847
+ Type::ImmutableString.new(true: "1", false: "0", **args)
848
+ end
849
+ ActiveRecord::Type.register(:string, adapter: :mysql2) do |_, **args|
850
+ Type::String.new(true: "1", false: "0", **args)
815
851
  end
816
-
817
- ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
818
852
  ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
819
853
  end
820
854
  end
@@ -5,6 +5,8 @@ module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  # An abstract definition of a column in a table.
7
7
  class Column
8
+ include Deduplicable
9
+
8
10
  attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
9
11
 
10
12
  delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
@@ -76,6 +78,7 @@ module ActiveRecord
76
78
  def hash
77
79
  Column.hash ^
78
80
  name.hash ^
81
+ name.encoding.hash ^
79
82
  default.hash ^
80
83
  sql_type_metadata.hash ^
81
84
  null.hash ^
@@ -83,10 +86,21 @@ module ActiveRecord
83
86
  collation.hash ^
84
87
  comment.hash
85
88
  end
89
+
90
+ private
91
+ def deduplicated
92
+ @name = -name
93
+ @sql_type_metadata = sql_type_metadata.deduplicate if sql_type_metadata
94
+ @default = -default if default
95
+ @default_function = -default_function if default_function
96
+ @collation = -collation if collation
97
+ @comment = -comment if comment
98
+ super
99
+ end
86
100
  end
87
101
 
88
102
  class NullColumn < Column
89
- def initialize(name)
103
+ def initialize(name, **)
90
104
  super(name, nil)
91
105
  end
92
106
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters # :nodoc:
5
+ module Deduplicable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def registry
10
+ @registry ||= {}
11
+ end
12
+
13
+ def new(*, **)
14
+ super.deduplicate
15
+ end
16
+ end
17
+
18
+ def deduplicate
19
+ self.class.registry[self] ||= deduplicated
20
+ end
21
+ alias :-@ :deduplicate
22
+
23
+ private
24
+ def deduplicated
25
+ freeze
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class LegacyPoolManager # :nodoc:
6
+ def initialize
7
+ @name_to_pool_config = {}
8
+ end
9
+
10
+ def shard_names
11
+ @name_to_pool_config.keys
12
+ end
13
+
14
+ def pool_configs(_ = nil)
15
+ @name_to_pool_config.values
16
+ end
17
+
18
+ def remove_pool_config(_, shard)
19
+ @name_to_pool_config.delete(shard)
20
+ end
21
+
22
+ def get_pool_config(_, shard)
23
+ @name_to_pool_config[shard]
24
+ end
25
+
26
+ def set_pool_config(role, shard, pool_config)
27
+ if pool_config
28
+ @name_to_pool_config[shard] = pool_config
29
+ else
30
+ raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  end
12
12
 
13
13
  def case_sensitive?
14
- collation && !/_ci\z/.match?(collation)
14
+ collation && !collation.end_with?("_ci")
15
15
  end
16
16
 
17
17
  def auto_increment?