activerecord 5.2.4.2 → 6.0.2.2

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 (269) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +715 -566
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/association_relation.rb +15 -6
  9. data/lib/active_record/associations.rb +20 -15
  10. data/lib/active_record/associations/association.rb +61 -20
  11. data/lib/active_record/associations/association_scope.rb +4 -6
  12. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  14. data/lib/active_record/associations/builder/association.rb +14 -18
  15. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +35 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +12 -23
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +7 -0
  24. data/lib/active_record/associations/has_many_association.rb +2 -10
  25. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  26. data/lib/active_record/associations/has_one_association.rb +28 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  28. data/lib/active_record/associations/join_dependency.rb +28 -28
  29. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  30. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  31. data/lib/active_record/associations/preloader.rb +39 -31
  32. data/lib/active_record/associations/preloader/association.rb +38 -36
  33. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  34. data/lib/active_record/associations/singular_association.rb +2 -16
  35. data/lib/active_record/attribute_assignment.rb +7 -10
  36. data/lib/active_record/attribute_methods.rb +28 -100
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  38. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  40. data/lib/active_record/attribute_methods/query.rb +2 -3
  41. data/lib/active_record/attribute_methods/read.rb +15 -53
  42. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  44. data/lib/active_record/attribute_methods/write.rb +17 -24
  45. data/lib/active_record/attributes.rb +13 -0
  46. data/lib/active_record/autosave_association.rb +2 -2
  47. data/lib/active_record/base.rb +2 -3
  48. data/lib/active_record/callbacks.rb +5 -19
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +104 -16
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
  61. data/lib/active_record/connection_adapters/column.rb +17 -13
  62. data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
  63. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  66. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  67. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  68. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  69. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  70. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  71. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  72. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  81. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  82. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  83. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  86. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  87. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  88. data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
  89. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  90. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  93. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  94. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
  95. data/lib/active_record/connection_handling.rb +155 -26
  96. data/lib/active_record/core.rb +103 -59
  97. data/lib/active_record/counter_cache.rb +4 -29
  98. data/lib/active_record/database_configurations.rb +233 -0
  99. data/lib/active_record/database_configurations/database_config.rb +37 -0
  100. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  101. data/lib/active_record/database_configurations/url_config.rb +79 -0
  102. data/lib/active_record/dynamic_matchers.rb +1 -1
  103. data/lib/active_record/enum.rb +37 -7
  104. data/lib/active_record/errors.rb +15 -7
  105. data/lib/active_record/explain.rb +1 -1
  106. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  107. data/lib/active_record/fixture_set/render_context.rb +17 -0
  108. data/lib/active_record/fixture_set/table_row.rb +153 -0
  109. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  110. data/lib/active_record/fixtures.rb +145 -472
  111. data/lib/active_record/gem_version.rb +3 -3
  112. data/lib/active_record/inheritance.rb +13 -3
  113. data/lib/active_record/insert_all.rb +179 -0
  114. data/lib/active_record/integration.rb +68 -16
  115. data/lib/active_record/internal_metadata.rb +10 -2
  116. data/lib/active_record/locking/optimistic.rb +5 -6
  117. data/lib/active_record/locking/pessimistic.rb +3 -3
  118. data/lib/active_record/log_subscriber.rb +7 -26
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  121. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/migration/command_recorder.rb +50 -6
  124. data/lib/active_record/migration/compatibility.rb +76 -49
  125. data/lib/active_record/model_schema.rb +33 -9
  126. data/lib/active_record/nested_attributes.rb +2 -2
  127. data/lib/active_record/no_touching.rb +7 -0
  128. data/lib/active_record/persistence.rb +228 -24
  129. data/lib/active_record/query_cache.rb +11 -4
  130. data/lib/active_record/querying.rb +32 -20
  131. data/lib/active_record/railtie.rb +80 -43
  132. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  133. data/lib/active_record/railties/controller_runtime.rb +30 -35
  134. data/lib/active_record/railties/databases.rake +199 -46
  135. data/lib/active_record/reflection.rb +32 -30
  136. data/lib/active_record/relation.rb +311 -80
  137. data/lib/active_record/relation/batches.rb +13 -10
  138. data/lib/active_record/relation/calculations.rb +53 -47
  139. data/lib/active_record/relation/delegation.rb +26 -43
  140. data/lib/active_record/relation/finder_methods.rb +23 -27
  141. data/lib/active_record/relation/merger.rb +11 -20
  142. data/lib/active_record/relation/predicate_builder.rb +4 -6
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  145. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  147. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  148. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  149. data/lib/active_record/relation/query_attribute.rb +13 -8
  150. data/lib/active_record/relation/query_methods.rb +213 -64
  151. data/lib/active_record/relation/spawn_methods.rb +1 -1
  152. data/lib/active_record/relation/where_clause.rb +14 -10
  153. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  154. data/lib/active_record/result.rb +30 -11
  155. data/lib/active_record/sanitization.rb +32 -40
  156. data/lib/active_record/schema.rb +2 -11
  157. data/lib/active_record/schema_dumper.rb +22 -7
  158. data/lib/active_record/schema_migration.rb +5 -1
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/scoping/default.rb +4 -5
  161. data/lib/active_record/scoping/named.rb +20 -15
  162. data/lib/active_record/statement_cache.rb +30 -3
  163. data/lib/active_record/store.rb +87 -8
  164. data/lib/active_record/table_metadata.rb +10 -17
  165. data/lib/active_record/tasks/database_tasks.rb +194 -25
  166. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  167. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  168. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  169. data/lib/active_record/test_databases.rb +23 -0
  170. data/lib/active_record/test_fixtures.rb +225 -0
  171. data/lib/active_record/timestamp.rb +39 -25
  172. data/lib/active_record/touch_later.rb +4 -2
  173. data/lib/active_record/transactions.rb +56 -65
  174. data/lib/active_record/translation.rb +1 -1
  175. data/lib/active_record/type.rb +3 -4
  176. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  177. data/lib/active_record/type_caster/connection.rb +15 -14
  178. data/lib/active_record/type_caster/map.rb +1 -4
  179. data/lib/active_record/validations.rb +1 -0
  180. data/lib/active_record/validations/uniqueness.rb +15 -27
  181. data/lib/arel.rb +58 -0
  182. data/lib/arel/alias_predication.rb +9 -0
  183. data/lib/arel/attributes.rb +22 -0
  184. data/lib/arel/attributes/attribute.rb +37 -0
  185. data/lib/arel/collectors/bind.rb +24 -0
  186. data/lib/arel/collectors/composite.rb +31 -0
  187. data/lib/arel/collectors/plain_string.rb +20 -0
  188. data/lib/arel/collectors/sql_string.rb +20 -0
  189. data/lib/arel/collectors/substitute_binds.rb +28 -0
  190. data/lib/arel/crud.rb +42 -0
  191. data/lib/arel/delete_manager.rb +18 -0
  192. data/lib/arel/errors.rb +9 -0
  193. data/lib/arel/expressions.rb +29 -0
  194. data/lib/arel/factory_methods.rb +49 -0
  195. data/lib/arel/insert_manager.rb +49 -0
  196. data/lib/arel/math.rb +45 -0
  197. data/lib/arel/nodes.rb +68 -0
  198. data/lib/arel/nodes/and.rb +32 -0
  199. data/lib/arel/nodes/ascending.rb +23 -0
  200. data/lib/arel/nodes/binary.rb +52 -0
  201. data/lib/arel/nodes/bind_param.rb +36 -0
  202. data/lib/arel/nodes/case.rb +55 -0
  203. data/lib/arel/nodes/casted.rb +50 -0
  204. data/lib/arel/nodes/comment.rb +29 -0
  205. data/lib/arel/nodes/count.rb +12 -0
  206. data/lib/arel/nodes/delete_statement.rb +45 -0
  207. data/lib/arel/nodes/descending.rb +23 -0
  208. data/lib/arel/nodes/equality.rb +18 -0
  209. data/lib/arel/nodes/extract.rb +24 -0
  210. data/lib/arel/nodes/false.rb +16 -0
  211. data/lib/arel/nodes/full_outer_join.rb +8 -0
  212. data/lib/arel/nodes/function.rb +44 -0
  213. data/lib/arel/nodes/grouping.rb +8 -0
  214. data/lib/arel/nodes/in.rb +8 -0
  215. data/lib/arel/nodes/infix_operation.rb +80 -0
  216. data/lib/arel/nodes/inner_join.rb +8 -0
  217. data/lib/arel/nodes/insert_statement.rb +37 -0
  218. data/lib/arel/nodes/join_source.rb +20 -0
  219. data/lib/arel/nodes/matches.rb +18 -0
  220. data/lib/arel/nodes/named_function.rb +23 -0
  221. data/lib/arel/nodes/node.rb +50 -0
  222. data/lib/arel/nodes/node_expression.rb +13 -0
  223. data/lib/arel/nodes/outer_join.rb +8 -0
  224. data/lib/arel/nodes/over.rb +15 -0
  225. data/lib/arel/nodes/regexp.rb +16 -0
  226. data/lib/arel/nodes/right_outer_join.rb +8 -0
  227. data/lib/arel/nodes/select_core.rb +67 -0
  228. data/lib/arel/nodes/select_statement.rb +41 -0
  229. data/lib/arel/nodes/sql_literal.rb +16 -0
  230. data/lib/arel/nodes/string_join.rb +11 -0
  231. data/lib/arel/nodes/table_alias.rb +27 -0
  232. data/lib/arel/nodes/terminal.rb +16 -0
  233. data/lib/arel/nodes/true.rb +16 -0
  234. data/lib/arel/nodes/unary.rb +45 -0
  235. data/lib/arel/nodes/unary_operation.rb +20 -0
  236. data/lib/arel/nodes/unqualified_column.rb +22 -0
  237. data/lib/arel/nodes/update_statement.rb +41 -0
  238. data/lib/arel/nodes/values_list.rb +9 -0
  239. data/lib/arel/nodes/window.rb +126 -0
  240. data/lib/arel/nodes/with.rb +11 -0
  241. data/lib/arel/order_predications.rb +13 -0
  242. data/lib/arel/predications.rb +257 -0
  243. data/lib/arel/select_manager.rb +271 -0
  244. data/lib/arel/table.rb +110 -0
  245. data/lib/arel/tree_manager.rb +72 -0
  246. data/lib/arel/update_manager.rb +34 -0
  247. data/lib/arel/visitors.rb +20 -0
  248. data/lib/arel/visitors/depth_first.rb +204 -0
  249. data/lib/arel/visitors/dot.rb +297 -0
  250. data/lib/arel/visitors/ibm_db.rb +34 -0
  251. data/lib/arel/visitors/informix.rb +62 -0
  252. data/lib/arel/visitors/mssql.rb +157 -0
  253. data/lib/arel/visitors/mysql.rb +83 -0
  254. data/lib/arel/visitors/oracle.rb +159 -0
  255. data/lib/arel/visitors/oracle12.rb +66 -0
  256. data/lib/arel/visitors/postgresql.rb +110 -0
  257. data/lib/arel/visitors/sqlite.rb +39 -0
  258. data/lib/arel/visitors/to_sql.rb +889 -0
  259. data/lib/arel/visitors/visitor.rb +46 -0
  260. data/lib/arel/visitors/where_sql.rb +23 -0
  261. data/lib/arel/window_predications.rb +9 -0
  262. data/lib/rails/generators/active_record/migration.rb +14 -1
  263. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  264. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  265. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  266. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  267. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  268. metadata +109 -24
  269. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -5,7 +5,7 @@ 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
+ attr_reader :name, :default, :sql_type_metadata, :null, :default_function, :collation, :comment
9
9
 
10
10
  delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
11
11
 
@@ -15,9 +15,8 @@ module ActiveRecord
15
15
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
16
16
  # +sql_type_metadata+ is various information about the type of the column
17
17
  # +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, **)
18
+ def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, **)
19
19
  @name = name.freeze
20
- @table_name = table_name
21
20
  @sql_type_metadata = sql_type_metadata
22
21
  @null = null
23
22
  @default = default
@@ -44,7 +43,6 @@ module ActiveRecord
44
43
 
45
44
  def init_with(coder)
46
45
  @name = coder["name"]
47
- @table_name = coder["table_name"]
48
46
  @sql_type_metadata = coder["sql_type_metadata"]
49
47
  @null = coder["null"]
50
48
  @default = coder["default"]
@@ -55,7 +53,6 @@ module ActiveRecord
55
53
 
56
54
  def encode_with(coder)
57
55
  coder["name"] = @name
58
- coder["table_name"] = @table_name
59
56
  coder["sql_type_metadata"] = @sql_type_metadata
60
57
  coder["null"] = @null
61
58
  coder["default"] = @default
@@ -66,19 +63,26 @@ module ActiveRecord
66
63
 
67
64
  def ==(other)
68
65
  other.is_a?(Column) &&
69
- attributes_for_hash == other.attributes_for_hash
66
+ name == other.name &&
67
+ default == other.default &&
68
+ sql_type_metadata == other.sql_type_metadata &&
69
+ null == other.null &&
70
+ default_function == other.default_function &&
71
+ collation == other.collation &&
72
+ comment == other.comment
70
73
  end
71
74
  alias :eql? :==
72
75
 
73
76
  def hash
74
- attributes_for_hash.hash
77
+ Column.hash ^
78
+ name.hash ^
79
+ default.hash ^
80
+ sql_type_metadata.hash ^
81
+ null.hash ^
82
+ default_function.hash ^
83
+ collation.hash ^
84
+ comment.hash
75
85
  end
76
-
77
- protected
78
-
79
- def attributes_for_hash
80
- [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
81
- end
82
86
  end
83
87
 
84
88
  class NullColumn < Column
@@ -57,9 +57,7 @@ module ActiveRecord
57
57
 
58
58
  private
59
59
 
60
- def uri
61
- @uri
62
- end
60
+ attr_reader :uri
63
61
 
64
62
  def uri_parser
65
63
  @uri_parser ||= URI::Parser.new
@@ -116,8 +114,7 @@ module ActiveRecord
116
114
  class Resolver # :nodoc:
117
115
  attr_reader :configurations
118
116
 
119
- # Accepts a hash two layers deep, keys on the first layer represent
120
- # environments such as "production". Keys must be strings.
117
+ # Accepts a list of db config objects.
121
118
  def initialize(configurations)
122
119
  @configurations = configurations
123
120
  end
@@ -138,34 +135,14 @@ module ActiveRecord
138
135
  # Resolver.new(configurations).resolve(:production)
139
136
  # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
140
137
  #
141
- def resolve(config)
142
- if config
143
- resolve_connection config
144
- elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call
145
- resolve_symbol_connection env.to_sym
138
+ def resolve(config_or_env, pool_name = nil)
139
+ if config_or_env
140
+ resolve_connection config_or_env, pool_name
146
141
  else
147
142
  raise AdapterNotSpecified
148
143
  end
149
144
  end
150
145
 
151
- # Expands each key in @configurations hash into fully resolved hash
152
- def resolve_all
153
- config = configurations.dup
154
-
155
- if env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
156
- env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
157
- end
158
-
159
- config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
160
- config.merge! env_config if env_config
161
-
162
- config.each do |key, value|
163
- config[key] = resolve(value) if value
164
- end
165
-
166
- config
167
- end
168
-
169
146
  # Returns an instance of ConnectionSpecification for a given adapter.
170
147
  # Accepts a hash one layer deep that contains all connection information.
171
148
  #
@@ -179,7 +156,9 @@ module ActiveRecord
179
156
  # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
180
157
  #
181
158
  def spec(config)
182
- spec = resolve(config).symbolize_keys
159
+ pool_name = config if config.is_a?(Symbol)
160
+
161
+ spec = resolve(config, pool_name).symbolize_keys
183
162
 
184
163
  raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
185
164
 
@@ -207,14 +186,13 @@ module ActiveRecord
207
186
  adapter_method = "#{spec[:adapter]}_connection"
208
187
 
209
188
  unless ActiveRecord::Base.respond_to?(adapter_method)
210
- raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
189
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
211
190
  end
212
191
 
213
192
  ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method)
214
193
  end
215
194
 
216
195
  private
217
-
218
196
  # Returns fully resolved connection, accepts hash, string or symbol.
219
197
  # Always returns a hash.
220
198
  #
@@ -235,32 +213,64 @@ module ActiveRecord
235
213
  # Resolver.new({}).resolve_connection("postgresql://localhost/foo")
236
214
  # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
237
215
  #
238
- def resolve_connection(spec)
239
- case spec
216
+ def resolve_connection(config_or_env, pool_name = nil)
217
+ case config_or_env
240
218
  when Symbol
241
- resolve_symbol_connection spec
219
+ resolve_symbol_connection config_or_env, pool_name
242
220
  when String
243
- resolve_url_connection spec
221
+ resolve_url_connection config_or_env
244
222
  when Hash
245
- resolve_hash_connection spec
223
+ resolve_hash_connection config_or_env
224
+ else
225
+ raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config_or_env.inspect}"
246
226
  end
247
227
  end
248
228
 
249
- # Takes the environment such as +:production+ or +:development+.
229
+ # Takes the environment such as +:production+ or +:development+ and a
230
+ # pool name the corresponds to the name given by the connection pool
231
+ # to the connection. That pool name is merged into the hash with the
232
+ # name key.
233
+ #
250
234
  # This requires that the @configurations was initialized with a key that
251
235
  # matches.
252
236
  #
253
- # Resolver.new("production" => {}).resolve_symbol_connection(:production)
254
- # # => {}
237
+ # configurations = #<ActiveRecord::DatabaseConfigurations:0x00007fd9fdace3e0
238
+ # @configurations=[
239
+ # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd9fdace250
240
+ # @env_name="production", @spec_name="primary", @config={"database"=>"my_db"}>
241
+ # ]>
255
242
  #
256
- def resolve_symbol_connection(spec)
257
- if config = configurations[spec.to_s]
258
- resolve_connection(config).merge("name" => spec.to_s)
243
+ # Resolver.new(configurations).resolve_symbol_connection(:production, "primary")
244
+ # # => { "database" => "my_db" }
245
+ def resolve_symbol_connection(env_name, pool_name)
246
+ db_config = configurations.find_db_config(env_name)
247
+
248
+ if db_config
249
+ resolve_connection(db_config.config).merge("name" => pool_name.to_s)
259
250
  else
260
- raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
251
+ raise AdapterNotSpecified, <<~MSG
252
+ The `#{env_name}` database is not configured for the `#{ActiveRecord::ConnectionHandling::DEFAULT_ENV.call}` environment.
253
+
254
+ Available databases configurations are:
255
+
256
+ #{build_configuration_sentence}
257
+ MSG
261
258
  end
262
259
  end
263
260
 
261
+ def build_configuration_sentence # :nodoc:
262
+ configs = configurations.configs_for(include_replicas: true)
263
+
264
+ configs.group_by(&:env_name).map do |env, config|
265
+ namespaces = config.map(&:spec_name)
266
+ if namespaces.size > 1
267
+ "#{env}: #{namespaces.join(", ")}"
268
+ else
269
+ env
270
+ end
271
+ end.join("\n")
272
+ end
273
+
264
274
  # Accepts a hash. Expands the "url" key that contains a
265
275
  # URL database connection to a full connection
266
276
  # hash and merges with the rest of the hash.
@@ -5,26 +5,22 @@ module ActiveRecord
5
5
  module DetermineIfPreparableVisitor
6
6
  attr_accessor :preparable
7
7
 
8
- def accept(*)
8
+ def accept(object, collector)
9
9
  @preparable = true
10
10
  super
11
11
  end
12
12
 
13
13
  def visit_Arel_Nodes_In(o, collector)
14
14
  @preparable = false
15
+ super
16
+ end
15
17
 
16
- if Array === o.right && !o.right.empty?
17
- o.right.delete_if do |bind|
18
- if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
19
- !bind.value.boundable?
20
- end
21
- end
22
- end
23
-
18
+ def visit_Arel_Nodes_NotIn(o, collector)
19
+ @preparable = false
24
20
  super
25
21
  end
26
22
 
27
- def visit_Arel_Nodes_SqlLiteral(*)
23
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
28
24
  @preparable = false
29
25
  super
30
26
  end
@@ -11,7 +11,7 @@ module ActiveRecord
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,21 @@ 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
+ :begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :describe, :desc, :with
24
+ ) # :nodoc:
25
+ private_constant :READ_QUERY
26
+
27
+ def write_query?(sql) # :nodoc:
28
+ !READ_QUERY.match?(sql)
29
+ end
30
+
22
31
  # Executes the SQL statement in the context of this connection.
23
32
  def execute(sql, name = nil)
33
+ if preventing_writes? && write_query?(sql)
34
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
35
+ end
36
+
24
37
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
25
38
  # made since we established the connection
26
39
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -31,18 +44,28 @@ module ActiveRecord
31
44
  def exec_query(sql, name = "SQL", binds = [], prepare: false)
32
45
  if without_prepared_statement?(binds)
33
46
  execute_and_free(sql, name) do |result|
34
- ActiveRecord::Result.new(result.fields, result.to_a) if result
47
+ if result
48
+ ActiveRecord::Result.new(result.fields, result.to_a)
49
+ else
50
+ ActiveRecord::Result.new([], [])
51
+ end
35
52
  end
36
53
  else
37
54
  exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
38
- ActiveRecord::Result.new(result.fields, result.to_a) if result
55
+ if result
56
+ ActiveRecord::Result.new(result.fields, result.to_a)
57
+ else
58
+ ActiveRecord::Result.new([], [])
59
+ end
39
60
  end
40
61
  end
41
62
  end
42
63
 
43
64
  def exec_delete(sql, name = nil, binds = [])
44
65
  if without_prepared_statement?(binds)
45
- execute_and_free(sql, name) { @connection.affected_rows }
66
+ @lock.synchronize do
67
+ execute_and_free(sql, name) { @connection.affected_rows }
68
+ end
46
69
  else
47
70
  exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
48
71
  end
@@ -50,22 +73,31 @@ module ActiveRecord
50
73
  alias :exec_update :exec_delete
51
74
 
52
75
  private
76
+ def execute_batch(sql, name = nil)
77
+ super
78
+ @connection.abandon_results!
79
+ end
80
+
53
81
  def default_insert_value(column)
54
- Arel.sql("DEFAULT") unless column.auto_increment?
82
+ super unless column.auto_increment?
55
83
  end
56
84
 
57
85
  def last_inserted_id(result)
58
86
  @connection.last_id
59
87
  end
60
88
 
61
- def discard_remaining_results
62
- @connection.next_result while @connection.more_results?
63
- end
64
-
65
89
  def supports_set_server_option?
66
90
  @connection.respond_to?(:set_server_option)
67
91
  end
68
92
 
93
+ def build_truncate_statements(*table_names)
94
+ if table_names.size == 1
95
+ super.first
96
+ else
97
+ super
98
+ end
99
+ end
100
+
69
101
  def multi_statements_enabled?(flags)
70
102
  if flags.is_a?(Array)
71
103
  flags.include?("MULTI_STATEMENTS")
@@ -98,7 +130,40 @@ module ActiveRecord
98
130
  end
99
131
  end
100
132
 
133
+ def combine_multi_statements(total_sql)
134
+ total_sql.each_with_object([]) do |sql, total_sql_chunks|
135
+ previous_packet = total_sql_chunks.last
136
+ if max_allowed_packet_reached?(sql, previous_packet)
137
+ total_sql_chunks << +sql
138
+ else
139
+ previous_packet << ";\n"
140
+ previous_packet << sql
141
+ end
142
+ end
143
+ end
144
+
145
+ def max_allowed_packet_reached?(current_packet, previous_packet)
146
+ if current_packet.bytesize > max_allowed_packet
147
+ raise ActiveRecordError,
148
+ "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
149
+ elsif previous_packet.nil?
150
+ true
151
+ else
152
+ (current_packet.bytesize + previous_packet.bytesize + 2) > max_allowed_packet
153
+ end
154
+ end
155
+
156
+ def max_allowed_packet
157
+ @max_allowed_packet ||= show_variable("max_allowed_packet")
158
+ end
159
+
101
160
  def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
161
+ if preventing_writes? && write_query?(sql)
162
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
163
+ end
164
+
165
+ materialize_transactions
166
+
102
167
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
103
168
  # made since we established the connection
104
169
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -107,10 +172,7 @@ module ActiveRecord
107
172
 
108
173
  log(sql, name, binds, type_casted_binds) do
109
174
  if cache_stmt
110
- cache = @statements[sql] ||= {
111
- stmt: @connection.prepare(sql)
112
- }
113
- stmt = cache[:stmt]
175
+ stmt = @statements[sql] ||= @connection.prepare(sql)
114
176
  else
115
177
  stmt = @connection.prepare(sql)
116
178
  end
@@ -5,11 +5,11 @@ module ActiveRecord
5
5
  module MySQL
6
6
  module Quoting # :nodoc:
7
7
  def quote_column_name(name)
8
- @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze
8
+ self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
9
9
  end
10
10
 
11
11
  def quote_table_name(name)
12
- @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
12
+ self.class.quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
13
13
  end
14
14
 
15
15
  def unquoted_true
@@ -32,12 +32,49 @@ module ActiveRecord
32
32
  "x'#{value.hex}'"
33
33
  end
34
34
 
35
- def _type_cast(value)
36
- case value
37
- when Date, Time then value
38
- else super
39
- end
35
+ def column_name_matcher
36
+ COLUMN_NAME
37
+ end
38
+
39
+ def column_name_with_order_matcher
40
+ COLUMN_NAME_WITH_ORDER
40
41
  end
42
+
43
+ COLUMN_NAME = /
44
+ \A
45
+ (
46
+ (?:
47
+ # `table_name`.`column_name` | function(one or no argument)
48
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
49
+ )
50
+ (?:\s+AS\s+(?:\w+|`\w+`))?
51
+ )
52
+ (?:\s*,\s*\g<1>)*
53
+ \z
54
+ /ix
55
+
56
+ COLUMN_NAME_WITH_ORDER = /
57
+ \A
58
+ (
59
+ (?:
60
+ # `table_name`.`column_name` | function(one or no argument)
61
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
62
+ )
63
+ (?:\s+ASC|\s+DESC)?
64
+ )
65
+ (?:\s*,\s*\g<1>)*
66
+ \z
67
+ /ix
68
+
69
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
70
+
71
+ private
72
+ def _type_cast(value)
73
+ case value
74
+ when Date, Time then value
75
+ else super
76
+ end
77
+ end
41
78
  end
42
79
  end
43
80
  end