activerecord 5.2.8.1 → 6.1.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1347 -624
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +16 -7
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +107 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +73 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +225 -121
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +341 -99
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +4 -4
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +113 -74
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +478 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +94 -10
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +291 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +118 -32
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -5,7 +5,9 @@ module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  # An abstract definition of a column in a table.
7
7
  class Column
8
- attr_reader :name, :default, :sql_type_metadata, :null, :table_name, :default_function, :collation, :comment
8
+ include Deduplicable
9
+
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
11
13
 
@@ -15,9 +17,8 @@ module ActiveRecord
15
17
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
16
18
  # +sql_type_metadata+ is various information about the type of the column
17
19
  # +null+ determines if this column allows +NULL+ values.
18
- def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
20
+ def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
19
21
  @name = name.freeze
20
- @table_name = table_name
21
22
  @sql_type_metadata = sql_type_metadata
22
23
  @null = null
23
24
  @default = default
@@ -44,7 +45,6 @@ module ActiveRecord
44
45
 
45
46
  def init_with(coder)
46
47
  @name = coder["name"]
47
- @table_name = coder["table_name"]
48
48
  @sql_type_metadata = coder["sql_type_metadata"]
49
49
  @null = coder["null"]
50
50
  @default = coder["default"]
@@ -55,7 +55,6 @@ module ActiveRecord
55
55
 
56
56
  def encode_with(coder)
57
57
  coder["name"] = @name
58
- coder["table_name"] = @table_name
59
58
  coder["sql_type_metadata"] = @sql_type_metadata
60
59
  coder["null"] = @null
61
60
  coder["default"] = @default
@@ -66,23 +65,42 @@ module ActiveRecord
66
65
 
67
66
  def ==(other)
68
67
  other.is_a?(Column) &&
69
- attributes_for_hash == other.attributes_for_hash
68
+ name == other.name &&
69
+ default == other.default &&
70
+ sql_type_metadata == other.sql_type_metadata &&
71
+ null == other.null &&
72
+ default_function == other.default_function &&
73
+ collation == other.collation &&
74
+ comment == other.comment
70
75
  end
71
76
  alias :eql? :==
72
77
 
73
78
  def hash
74
- attributes_for_hash.hash
79
+ Column.hash ^
80
+ name.hash ^
81
+ name.encoding.hash ^
82
+ default.hash ^
83
+ sql_type_metadata.hash ^
84
+ null.hash ^
85
+ default_function.hash ^
86
+ collation.hash ^
87
+ comment.hash
75
88
  end
76
89
 
77
- protected
78
-
79
- def attributes_for_hash
80
- [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
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
81
99
  end
82
100
  end
83
101
 
84
102
  class NullColumn < Column
85
- def initialize(name)
103
+ def initialize(name, **)
86
104
  super(name, nil)
87
105
  end
88
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?
@@ -5,13 +5,13 @@ module ActiveRecord
5
5
  module MySQL
6
6
  module DatabaseStatements
7
7
  # Returns an ActiveRecord::Result instance.
8
- def select_all(*) # :nodoc:
8
+ def select_all(*, **) # :nodoc:
9
9
  result = if ExplainRegistry.collect? && prepared_statements
10
10
  unprepared_statement { super }
11
11
  else
12
12
  super
13
13
  end
14
- discard_remaining_results
14
+ @connection.abandon_results!
15
15
  result
16
16
  end
17
17
 
@@ -19,8 +19,32 @@ module ActiveRecord
19
19
  execute(sql, name).to_a
20
20
  end
21
21
 
22
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
23
+ :desc, :describe, :set, :show, :use
24
+ ) # :nodoc:
25
+ private_constant :READ_QUERY
26
+
27
+ def write_query?(sql) # :nodoc:
28
+ !READ_QUERY.match?(sql)
29
+ rescue ArgumentError # Invalid encoding
30
+ !READ_QUERY.match?(sql.b)
31
+ end
32
+
33
+ def explain(arel, binds = [])
34
+ sql = "EXPLAIN #{to_sql(arel, binds)}"
35
+ start = Concurrent.monotonic_time
36
+ result = exec_query(sql, "EXPLAIN", binds)
37
+ elapsed = Concurrent.monotonic_time - start
38
+
39
+ MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
40
+ end
41
+
22
42
  # Executes the SQL statement in the context of this connection.
23
43
  def execute(sql, name = nil)
44
+ if preventing_writes? && write_query?(sql)
45
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
46
+ end
47
+
24
48
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
25
49
  # made since we established the connection
26
50
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -31,18 +55,28 @@ module ActiveRecord
31
55
  def exec_query(sql, name = "SQL", binds = [], prepare: false)
32
56
  if without_prepared_statement?(binds)
33
57
  execute_and_free(sql, name) do |result|
34
- ActiveRecord::Result.new(result.fields, result.to_a) if result
58
+ if result
59
+ build_result(columns: result.fields, rows: result.to_a)
60
+ else
61
+ build_result(columns: [], rows: [])
62
+ end
35
63
  end
36
64
  else
37
65
  exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
38
- ActiveRecord::Result.new(result.fields, result.to_a) if result
66
+ if result
67
+ build_result(columns: result.fields, rows: result.to_a)
68
+ else
69
+ build_result(columns: [], rows: [])
70
+ end
39
71
  end
40
72
  end
41
73
  end
42
74
 
43
75
  def exec_delete(sql, name = nil, binds = [])
44
76
  if without_prepared_statement?(binds)
45
- execute_and_free(sql, name) { @connection.affected_rows }
77
+ @lock.synchronize do
78
+ execute_and_free(sql, name) { @connection.affected_rows }
79
+ end
46
80
  else
47
81
  exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
48
82
  end
@@ -50,55 +84,80 @@ module ActiveRecord
50
84
  alias :exec_update :exec_delete
51
85
 
52
86
  private
87
+ def execute_batch(statements, name = nil)
88
+ combine_multi_statements(statements).each do |statement|
89
+ execute(statement, name)
90
+ end
91
+ @connection.abandon_results!
92
+ end
93
+
53
94
  def default_insert_value(column)
54
- Arel.sql("DEFAULT") unless column.auto_increment?
95
+ super unless column.auto_increment?
55
96
  end
56
97
 
57
98
  def last_inserted_id(result)
58
99
  @connection.last_id
59
100
  end
60
101
 
61
- def discard_remaining_results
62
- @connection.next_result while @connection.more_results?
63
- end
102
+ def multi_statements_enabled?
103
+ flags = @config[:flags]
64
104
 
65
- def supports_set_server_option?
66
- @connection.respond_to?(:set_server_option)
67
- end
68
-
69
- def multi_statements_enabled?(flags)
70
105
  if flags.is_a?(Array)
71
106
  flags.include?("MULTI_STATEMENTS")
72
107
  else
73
- (flags & Mysql2::Client::MULTI_STATEMENTS) != 0
108
+ flags.anybits?(Mysql2::Client::MULTI_STATEMENTS)
74
109
  end
75
110
  end
76
111
 
77
112
  def with_multi_statements
78
- previous_flags = @config[:flags]
113
+ multi_statements_was = multi_statements_enabled?
79
114
 
80
- unless multi_statements_enabled?(previous_flags)
81
- if supports_set_server_option?
82
- @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
83
- else
84
- @config[:flags] = Mysql2::Client::MULTI_STATEMENTS
85
- reconnect!
86
- end
115
+ unless multi_statements_was
116
+ @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
87
117
  end
88
118
 
89
119
  yield
90
120
  ensure
91
- unless multi_statements_enabled?(previous_flags)
92
- if supports_set_server_option?
93
- @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
121
+ unless multi_statements_was
122
+ @connection.set_server_option(Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
123
+ end
124
+ end
125
+
126
+ def combine_multi_statements(total_sql)
127
+ total_sql.each_with_object([]) do |sql, total_sql_chunks|
128
+ previous_packet = total_sql_chunks.last
129
+ if max_allowed_packet_reached?(sql, previous_packet)
130
+ total_sql_chunks << +sql
94
131
  else
95
- @config[:flags] = previous_flags
96
- reconnect!
132
+ previous_packet << ";\n"
133
+ previous_packet << sql
97
134
  end
98
135
  end
99
136
  end
100
137
 
138
+ def max_allowed_packet_reached?(current_packet, previous_packet)
139
+ if current_packet.bytesize > max_allowed_packet
140
+ raise ActiveRecordError,
141
+ "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
142
+ elsif previous_packet.nil?
143
+ true
144
+ else
145
+ (current_packet.bytesize + previous_packet.bytesize + 2) > max_allowed_packet
146
+ end
147
+ end
148
+
149
+ def max_allowed_packet
150
+ @max_allowed_packet ||= show_variable("max_allowed_packet")
151
+ end
152
+
101
153
  def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
154
+ if preventing_writes? && write_query?(sql)
155
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
156
+ end
157
+
158
+ materialize_transactions
159
+ mark_transaction_written_if_write(sql)
160
+
102
161
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
103
162
  # made since we established the connection
104
163
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -107,10 +166,7 @@ module ActiveRecord
107
166
 
108
167
  log(sql, name, binds, type_casted_binds) do
109
168
  if cache_stmt
110
- cache = @statements[sql] ||= {
111
- stmt: @connection.prepare(sql)
112
- }
113
- stmt = cache[:stmt]
169
+ stmt = @statements[sql] ||= @connection.prepare(sql)
114
170
  else
115
171
  stmt = @connection.prepare(sql)
116
172
  end
@@ -37,7 +37,6 @@ module ActiveRecord
37
37
  end
38
38
 
39
39
  private
40
-
41
40
  def compute_column_widths(result)
42
41
  [].tap do |widths|
43
42
  result.columns.each_with_index do |column, i|
@@ -57,7 +56,7 @@ module ActiveRecord
57
56
  items.each_with_index do |item, i|
58
57
  item = "NULL" if item.nil?
59
58
  justifier = item.is_a?(Numeric) ? "rjust" : "ljust"
60
- cells << item.to_s.send(justifier, widths[i])
59
+ cells << item.to_s.public_send(justifier, widths[i])
61
60
  end
62
61
  "| " + cells.join(" | ") + " |"
63
62
  end
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/time_with_zone"
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters
5
7
  module MySQL
6
8
  module Quoting # :nodoc:
7
9
  def quote_column_name(name)
8
- @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze
10
+ self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
9
11
  end
10
12
 
11
13
  def quote_table_name(name)
12
- @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
14
+ self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
13
15
  end
14
16
 
15
17
  def unquoted_true
@@ -32,12 +34,62 @@ module ActiveRecord
32
34
  "x'#{value.hex}'"
33
35
  end
34
36
 
35
- def _type_cast(value)
36
- case value
37
- when Date, Time then value
38
- else super
39
- end
37
+ def column_name_matcher
38
+ COLUMN_NAME
40
39
  end
40
+
41
+ def column_name_with_order_matcher
42
+ COLUMN_NAME_WITH_ORDER
43
+ end
44
+
45
+ COLUMN_NAME = /
46
+ \A
47
+ (
48
+ (?:
49
+ # `table_name`.`column_name` | function(one or no argument)
50
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
51
+ )
52
+ (?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
53
+ )
54
+ (?:\s*,\s*\g<1>)*
55
+ \z
56
+ /ix
57
+
58
+ COLUMN_NAME_WITH_ORDER = /
59
+ \A
60
+ (
61
+ (?:
62
+ # `table_name`.`column_name` | function(one or no argument)
63
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
64
+ )
65
+ (?:\s+ASC|\s+DESC)?
66
+ )
67
+ (?:\s*,\s*\g<1>)*
68
+ \z
69
+ /ix
70
+
71
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
72
+
73
+ private
74
+ # Override +_type_cast+ we pass to mysql2 Date and Time objects instead
75
+ # of Strings since mysql2 is able to handle those classes more efficiently.
76
+ def _type_cast(value)
77
+ case value
78
+ when ActiveSupport::TimeWithZone
79
+ # We need to check explicitly for ActiveSupport::TimeWithZone because
80
+ # we need to transform it to Time objects but we don't want to
81
+ # transform Time objects to themselves.
82
+ if ActiveRecord::Base.default_timezone == :utc
83
+ value.getutc
84
+ else
85
+ value.getlocal
86
+ end
87
+ when Date, Time
88
+ value
89
+ else
90
+ super
91
+ end
92
+ end
41
93
  end
42
94
  end
43
95
  end
@@ -3,34 +3,58 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module MySQL
6
- class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc:
7
- delegate :add_sql_comment!, :mariadb?, to: :@conn
8
- private :add_sql_comment!, :mariadb?
6
+ class SchemaCreation < SchemaCreation # :nodoc:
7
+ delegate :add_sql_comment!, :mariadb?, to: :@conn, private: true
9
8
 
10
9
  private
11
-
12
10
  def visit_DropForeignKey(name)
13
11
  "DROP FOREIGN KEY #{name}"
14
12
  end
15
13
 
14
+ def visit_DropCheckConstraint(name)
15
+ "DROP #{mariadb? ? 'CONSTRAINT' : 'CHECK'} #{name}"
16
+ end
17
+
16
18
  def visit_AddColumnDefinition(o)
17
19
  add_column_position!(super, column_options(o.column))
18
20
  end
19
21
 
20
22
  def visit_ChangeColumnDefinition(o)
21
- change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}".dup
23
+ change_column_sql = +"CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
22
24
  add_column_position!(change_column_sql, column_options(o.column))
23
25
  end
24
26
 
25
- def add_table_options!(create_sql, options)
26
- add_sql_comment!(super, options[:comment])
27
+ def visit_CreateIndexDefinition(o)
28
+ sql = visit_IndexDefinition(o.index, true)
29
+ sql << " #{o.algorithm}" if o.algorithm
30
+ sql
31
+ end
32
+
33
+ def visit_IndexDefinition(o, create = false)
34
+ index_type = o.type&.to_s&.upcase || o.unique && "UNIQUE"
35
+
36
+ sql = create ? ["CREATE"] : []
37
+ sql << index_type if index_type
38
+ sql << "INDEX"
39
+ sql << quote_column_name(o.name)
40
+ sql << "USING #{o.using}" if o.using
41
+ sql << "ON #{quote_table_name(o.table)}" if create
42
+ sql << "(#{quoted_columns(o)})"
43
+
44
+ add_sql_comment!(sql.join(" "), o.comment)
45
+ end
46
+
47
+ def add_table_options!(create_sql, o)
48
+ create_sql << " DEFAULT CHARSET=#{o.charset}" if o.charset
49
+ create_sql << " COLLATE=#{o.collation}" if o.collation
50
+ add_sql_comment!(super, o.comment)
27
51
  end
28
52
 
29
53
  def add_column_options!(sql, options)
30
54
  # By default, TIMESTAMP columns are NOT NULL, cannot contain NULL values,
31
55
  # and assigning NULL assigns the current timestamp. To permit a TIMESTAMP
32
56
  # column to contain NULL, explicitly declare it with the NULL attribute.
33
- # See https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
57
+ # See https://dev.mysql.com/doc/refman/en/timestamp-initialization.html
34
58
  if /\Atimestamp\b/.match?(options[:column].sql_type) && !options[:primary_key]
35
59
  sql << " NULL" unless options[:null] == false || options_include_default?(options)
36
60
  end
@@ -64,8 +88,8 @@ module ActiveRecord
64
88
  end
65
89
 
66
90
  def index_in_create(table_name, column_name, options)
67
- index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
68
- add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})".dup, comment)
91
+ index, _ = @conn.add_index_options(table_name, column_name, **options)
92
+ accept(index)
69
93
  end
70
94
  end
71
95
  end
@@ -4,54 +4,70 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module MySQL
6
6
  module ColumnMethods
7
- def blob(*args, **options)
8
- args.each { |name| column(name, :blob, options) }
9
- end
7
+ extend ActiveSupport::Concern
10
8
 
11
- def tinyblob(*args, **options)
12
- args.each { |name| column(name, :tinyblob, options) }
13
- end
9
+ ##
10
+ # :method: blob
11
+ # :call-seq: blob(*names, **options)
14
12
 
15
- def mediumblob(*args, **options)
16
- args.each { |name| column(name, :mediumblob, options) }
17
- end
13
+ ##
14
+ # :method: tinyblob
15
+ # :call-seq: tinyblob(*names, **options)
18
16
 
19
- def longblob(*args, **options)
20
- args.each { |name| column(name, :longblob, options) }
21
- end
17
+ ##
18
+ # :method: mediumblob
19
+ # :call-seq: mediumblob(*names, **options)
22
20
 
23
- def tinytext(*args, **options)
24
- args.each { |name| column(name, :tinytext, options) }
25
- end
21
+ ##
22
+ # :method: longblob
23
+ # :call-seq: longblob(*names, **options)
26
24
 
27
- def mediumtext(*args, **options)
28
- args.each { |name| column(name, :mediumtext, options) }
29
- end
25
+ ##
26
+ # :method: tinytext
27
+ # :call-seq: tinytext(*names, **options)
30
28
 
31
- def longtext(*args, **options)
32
- args.each { |name| column(name, :longtext, options) }
33
- end
29
+ ##
30
+ # :method: mediumtext
31
+ # :call-seq: mediumtext(*names, **options)
34
32
 
35
- def unsigned_integer(*args, **options)
36
- args.each { |name| column(name, :unsigned_integer, options) }
37
- end
33
+ ##
34
+ # :method: longtext
35
+ # :call-seq: longtext(*names, **options)
38
36
 
39
- def unsigned_bigint(*args, **options)
40
- args.each { |name| column(name, :unsigned_bigint, options) }
41
- end
37
+ ##
38
+ # :method: unsigned_integer
39
+ # :call-seq: unsigned_integer(*names, **options)
42
40
 
43
- def unsigned_float(*args, **options)
44
- args.each { |name| column(name, :unsigned_float, options) }
45
- end
41
+ ##
42
+ # :method: unsigned_bigint
43
+ # :call-seq: unsigned_bigint(*names, **options)
44
+
45
+ ##
46
+ # :method: unsigned_float
47
+ # :call-seq: unsigned_float(*names, **options)
48
+
49
+ ##
50
+ # :method: unsigned_decimal
51
+ # :call-seq: unsigned_decimal(*names, **options)
46
52
 
47
- def unsigned_decimal(*args, **options)
48
- args.each { |name| column(name, :unsigned_decimal, options) }
53
+ included do
54
+ define_column_methods :blob, :tinyblob, :mediumblob, :longblob,
55
+ :tinytext, :mediumtext, :longtext, :unsigned_integer, :unsigned_bigint,
56
+ :unsigned_float, :unsigned_decimal
49
57
  end
50
58
  end
51
59
 
52
60
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
53
61
  include ColumnMethods
54
62
 
63
+ attr_reader :charset, :collation
64
+
65
+ def initialize(conn, name, charset: nil, collation: nil, **)
66
+ super
67
+ @charset = charset
68
+ @collation = collation
69
+ end
70
+
55
71
  def new_column_definition(name, type, **options) # :nodoc:
56
72
  case type
57
73
  when :virtual