activerecord 5.2.4.3 → 6.0.0

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 (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +614 -588
  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/associations.rb +19 -14
  9. data/lib/active_record/associations/association.rb +52 -19
  10. data/lib/active_record/associations/association_scope.rb +4 -6
  11. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  13. data/lib/active_record/associations/builder/association.rb +14 -18
  14. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  15. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  17. data/lib/active_record/associations/builder/has_many.rb +2 -0
  18. data/lib/active_record/associations/builder/has_one.rb +35 -1
  19. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  20. data/lib/active_record/associations/collection_association.rb +6 -21
  21. data/lib/active_record/associations/collection_proxy.rb +12 -15
  22. data/lib/active_record/associations/foreign_association.rb +7 -0
  23. data/lib/active_record/associations/has_many_association.rb +2 -10
  24. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  25. data/lib/active_record/associations/has_one_association.rb +28 -30
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency.rb +24 -28
  28. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  29. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +40 -32
  31. data/lib/active_record/associations/preloader/association.rb +38 -36
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/singular_association.rb +2 -16
  34. data/lib/active_record/attribute_assignment.rb +7 -10
  35. data/lib/active_record/attribute_methods.rb +28 -100
  36. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  37. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  38. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  39. data/lib/active_record/attribute_methods/query.rb +2 -3
  40. data/lib/active_record/attribute_methods/read.rb +15 -53
  41. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  42. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  43. data/lib/active_record/attribute_methods/write.rb +17 -24
  44. data/lib/active_record/attributes.rb +13 -0
  45. data/lib/active_record/autosave_association.rb +5 -9
  46. data/lib/active_record/base.rb +2 -3
  47. data/lib/active_record/callbacks.rb +5 -19
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
  60. data/lib/active_record/connection_adapters/column.rb +17 -13
  61. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  62. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  69. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  70. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  75. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  78. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  79. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  81. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  83. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  86. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  87. data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
  88. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  89. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  90. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  91. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  92. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
  94. data/lib/active_record/connection_handling.rb +149 -27
  95. data/lib/active_record/core.rb +100 -60
  96. data/lib/active_record/counter_cache.rb +4 -29
  97. data/lib/active_record/database_configurations.rb +233 -0
  98. data/lib/active_record/database_configurations/database_config.rb +37 -0
  99. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  100. data/lib/active_record/database_configurations/url_config.rb +79 -0
  101. data/lib/active_record/dynamic_matchers.rb +1 -1
  102. data/lib/active_record/enum.rb +37 -7
  103. data/lib/active_record/errors.rb +15 -7
  104. data/lib/active_record/explain.rb +1 -1
  105. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  106. data/lib/active_record/fixture_set/render_context.rb +17 -0
  107. data/lib/active_record/fixture_set/table_row.rb +153 -0
  108. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  109. data/lib/active_record/fixtures.rb +145 -472
  110. data/lib/active_record/gem_version.rb +4 -4
  111. data/lib/active_record/inheritance.rb +13 -3
  112. data/lib/active_record/insert_all.rb +179 -0
  113. data/lib/active_record/integration.rb +68 -16
  114. data/lib/active_record/internal_metadata.rb +10 -2
  115. data/lib/active_record/locking/optimistic.rb +5 -6
  116. data/lib/active_record/locking/pessimistic.rb +3 -3
  117. data/lib/active_record/log_subscriber.rb +7 -26
  118. data/lib/active_record/middleware/database_selector.rb +75 -0
  119. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  120. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  121. data/lib/active_record/migration.rb +100 -81
  122. data/lib/active_record/migration/command_recorder.rb +50 -6
  123. data/lib/active_record/migration/compatibility.rb +76 -49
  124. data/lib/active_record/model_schema.rb +30 -9
  125. data/lib/active_record/nested_attributes.rb +2 -2
  126. data/lib/active_record/no_touching.rb +7 -0
  127. data/lib/active_record/persistence.rb +228 -24
  128. data/lib/active_record/query_cache.rb +11 -4
  129. data/lib/active_record/querying.rb +32 -20
  130. data/lib/active_record/railtie.rb +80 -43
  131. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  132. data/lib/active_record/railties/controller_runtime.rb +30 -35
  133. data/lib/active_record/railties/databases.rake +196 -46
  134. data/lib/active_record/reflection.rb +32 -30
  135. data/lib/active_record/relation.rb +310 -80
  136. data/lib/active_record/relation/batches.rb +13 -10
  137. data/lib/active_record/relation/calculations.rb +53 -47
  138. data/lib/active_record/relation/delegation.rb +26 -43
  139. data/lib/active_record/relation/finder_methods.rb +13 -26
  140. data/lib/active_record/relation/merger.rb +11 -20
  141. data/lib/active_record/relation/predicate_builder.rb +4 -6
  142. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  143. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  144. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  145. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  146. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  147. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  148. data/lib/active_record/relation/query_attribute.rb +13 -8
  149. data/lib/active_record/relation/query_methods.rb +189 -63
  150. data/lib/active_record/relation/spawn_methods.rb +1 -1
  151. data/lib/active_record/relation/where_clause.rb +14 -10
  152. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  153. data/lib/active_record/result.rb +30 -11
  154. data/lib/active_record/sanitization.rb +32 -40
  155. data/lib/active_record/schema.rb +2 -11
  156. data/lib/active_record/schema_dumper.rb +22 -7
  157. data/lib/active_record/schema_migration.rb +5 -1
  158. data/lib/active_record/scoping.rb +8 -8
  159. data/lib/active_record/scoping/default.rb +4 -5
  160. data/lib/active_record/scoping/named.rb +19 -15
  161. data/lib/active_record/statement_cache.rb +30 -3
  162. data/lib/active_record/store.rb +87 -8
  163. data/lib/active_record/table_metadata.rb +10 -17
  164. data/lib/active_record/tasks/database_tasks.rb +194 -25
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  168. data/lib/active_record/test_databases.rb +23 -0
  169. data/lib/active_record/test_fixtures.rb +224 -0
  170. data/lib/active_record/timestamp.rb +39 -25
  171. data/lib/active_record/touch_later.rb +4 -2
  172. data/lib/active_record/transactions.rb +57 -66
  173. data/lib/active_record/translation.rb +1 -1
  174. data/lib/active_record/type.rb +3 -4
  175. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  176. data/lib/active_record/type_caster/connection.rb +15 -14
  177. data/lib/active_record/type_caster/map.rb +1 -4
  178. data/lib/active_record/validations.rb +1 -0
  179. data/lib/active_record/validations/uniqueness.rb +15 -27
  180. data/lib/arel.rb +51 -0
  181. data/lib/arel/alias_predication.rb +9 -0
  182. data/lib/arel/attributes.rb +22 -0
  183. data/lib/arel/attributes/attribute.rb +37 -0
  184. data/lib/arel/collectors/bind.rb +24 -0
  185. data/lib/arel/collectors/composite.rb +31 -0
  186. data/lib/arel/collectors/plain_string.rb +20 -0
  187. data/lib/arel/collectors/sql_string.rb +20 -0
  188. data/lib/arel/collectors/substitute_binds.rb +28 -0
  189. data/lib/arel/crud.rb +42 -0
  190. data/lib/arel/delete_manager.rb +18 -0
  191. data/lib/arel/errors.rb +9 -0
  192. data/lib/arel/expressions.rb +29 -0
  193. data/lib/arel/factory_methods.rb +49 -0
  194. data/lib/arel/insert_manager.rb +49 -0
  195. data/lib/arel/math.rb +45 -0
  196. data/lib/arel/nodes.rb +68 -0
  197. data/lib/arel/nodes/and.rb +32 -0
  198. data/lib/arel/nodes/ascending.rb +23 -0
  199. data/lib/arel/nodes/binary.rb +52 -0
  200. data/lib/arel/nodes/bind_param.rb +36 -0
  201. data/lib/arel/nodes/case.rb +55 -0
  202. data/lib/arel/nodes/casted.rb +50 -0
  203. data/lib/arel/nodes/comment.rb +29 -0
  204. data/lib/arel/nodes/count.rb +12 -0
  205. data/lib/arel/nodes/delete_statement.rb +45 -0
  206. data/lib/arel/nodes/descending.rb +23 -0
  207. data/lib/arel/nodes/equality.rb +18 -0
  208. data/lib/arel/nodes/extract.rb +24 -0
  209. data/lib/arel/nodes/false.rb +16 -0
  210. data/lib/arel/nodes/full_outer_join.rb +8 -0
  211. data/lib/arel/nodes/function.rb +44 -0
  212. data/lib/arel/nodes/grouping.rb +8 -0
  213. data/lib/arel/nodes/in.rb +8 -0
  214. data/lib/arel/nodes/infix_operation.rb +80 -0
  215. data/lib/arel/nodes/inner_join.rb +8 -0
  216. data/lib/arel/nodes/insert_statement.rb +37 -0
  217. data/lib/arel/nodes/join_source.rb +20 -0
  218. data/lib/arel/nodes/matches.rb +18 -0
  219. data/lib/arel/nodes/named_function.rb +23 -0
  220. data/lib/arel/nodes/node.rb +50 -0
  221. data/lib/arel/nodes/node_expression.rb +13 -0
  222. data/lib/arel/nodes/outer_join.rb +8 -0
  223. data/lib/arel/nodes/over.rb +15 -0
  224. data/lib/arel/nodes/regexp.rb +16 -0
  225. data/lib/arel/nodes/right_outer_join.rb +8 -0
  226. data/lib/arel/nodes/select_core.rb +67 -0
  227. data/lib/arel/nodes/select_statement.rb +41 -0
  228. data/lib/arel/nodes/sql_literal.rb +16 -0
  229. data/lib/arel/nodes/string_join.rb +11 -0
  230. data/lib/arel/nodes/table_alias.rb +27 -0
  231. data/lib/arel/nodes/terminal.rb +16 -0
  232. data/lib/arel/nodes/true.rb +16 -0
  233. data/lib/arel/nodes/unary.rb +45 -0
  234. data/lib/arel/nodes/unary_operation.rb +20 -0
  235. data/lib/arel/nodes/unqualified_column.rb +22 -0
  236. data/lib/arel/nodes/update_statement.rb +41 -0
  237. data/lib/arel/nodes/values_list.rb +9 -0
  238. data/lib/arel/nodes/window.rb +126 -0
  239. data/lib/arel/nodes/with.rb +11 -0
  240. data/lib/arel/order_predications.rb +13 -0
  241. data/lib/arel/predications.rb +257 -0
  242. data/lib/arel/select_manager.rb +271 -0
  243. data/lib/arel/table.rb +110 -0
  244. data/lib/arel/tree_manager.rb +72 -0
  245. data/lib/arel/update_manager.rb +34 -0
  246. data/lib/arel/visitors.rb +20 -0
  247. data/lib/arel/visitors/depth_first.rb +204 -0
  248. data/lib/arel/visitors/dot.rb +297 -0
  249. data/lib/arel/visitors/ibm_db.rb +34 -0
  250. data/lib/arel/visitors/informix.rb +62 -0
  251. data/lib/arel/visitors/mssql.rb +157 -0
  252. data/lib/arel/visitors/mysql.rb +83 -0
  253. data/lib/arel/visitors/oracle.rb +159 -0
  254. data/lib/arel/visitors/oracle12.rb +66 -0
  255. data/lib/arel/visitors/postgresql.rb +110 -0
  256. data/lib/arel/visitors/sqlite.rb +39 -0
  257. data/lib/arel/visitors/to_sql.rb +889 -0
  258. data/lib/arel/visitors/visitor.rb +46 -0
  259. data/lib/arel/visitors/where_sql.rb +23 -0
  260. data/lib/arel/window_predications.rb +9 -0
  261. data/lib/rails/generators/active_record/migration.rb +14 -1
  262. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  263. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  264. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  265. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  266. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  267. metadata +108 -26
  268. 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
 
@@ -214,7 +193,6 @@ module ActiveRecord
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,19 @@ module ActiveRecord
19
19
  execute(sql, name).to_a
20
20
  end
21
21
 
22
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback) # :nodoc:
23
+ private_constant :READ_QUERY
24
+
25
+ def write_query?(sql) # :nodoc:
26
+ !READ_QUERY.match?(sql)
27
+ end
28
+
22
29
  # Executes the SQL statement in the context of this connection.
23
30
  def execute(sql, name = nil)
31
+ if preventing_writes? && write_query?(sql)
32
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
33
+ end
34
+
24
35
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
25
36
  # made since we established the connection
26
37
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -31,18 +42,28 @@ module ActiveRecord
31
42
  def exec_query(sql, name = "SQL", binds = [], prepare: false)
32
43
  if without_prepared_statement?(binds)
33
44
  execute_and_free(sql, name) do |result|
34
- ActiveRecord::Result.new(result.fields, result.to_a) if result
45
+ if result
46
+ ActiveRecord::Result.new(result.fields, result.to_a)
47
+ else
48
+ ActiveRecord::Result.new([], [])
49
+ end
35
50
  end
36
51
  else
37
52
  exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
38
- ActiveRecord::Result.new(result.fields, result.to_a) if result
53
+ if result
54
+ ActiveRecord::Result.new(result.fields, result.to_a)
55
+ else
56
+ ActiveRecord::Result.new([], [])
57
+ end
39
58
  end
40
59
  end
41
60
  end
42
61
 
43
62
  def exec_delete(sql, name = nil, binds = [])
44
63
  if without_prepared_statement?(binds)
45
- execute_and_free(sql, name) { @connection.affected_rows }
64
+ @lock.synchronize do
65
+ execute_and_free(sql, name) { @connection.affected_rows }
66
+ end
46
67
  else
47
68
  exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
48
69
  end
@@ -50,22 +71,31 @@ module ActiveRecord
50
71
  alias :exec_update :exec_delete
51
72
 
52
73
  private
74
+ def execute_batch(sql, name = nil)
75
+ super
76
+ @connection.abandon_results!
77
+ end
78
+
53
79
  def default_insert_value(column)
54
- Arel.sql("DEFAULT") unless column.auto_increment?
80
+ super unless column.auto_increment?
55
81
  end
56
82
 
57
83
  def last_inserted_id(result)
58
84
  @connection.last_id
59
85
  end
60
86
 
61
- def discard_remaining_results
62
- @connection.next_result while @connection.more_results?
63
- end
64
-
65
87
  def supports_set_server_option?
66
88
  @connection.respond_to?(:set_server_option)
67
89
  end
68
90
 
91
+ def build_truncate_statements(*table_names)
92
+ if table_names.size == 1
93
+ super.first
94
+ else
95
+ super
96
+ end
97
+ end
98
+
69
99
  def multi_statements_enabled?(flags)
70
100
  if flags.is_a?(Array)
71
101
  flags.include?("MULTI_STATEMENTS")
@@ -98,7 +128,40 @@ module ActiveRecord
98
128
  end
99
129
  end
100
130
 
131
+ def combine_multi_statements(total_sql)
132
+ total_sql.each_with_object([]) do |sql, total_sql_chunks|
133
+ previous_packet = total_sql_chunks.last
134
+ if max_allowed_packet_reached?(sql, previous_packet)
135
+ total_sql_chunks << +sql
136
+ else
137
+ previous_packet << ";\n"
138
+ previous_packet << sql
139
+ end
140
+ end
141
+ end
142
+
143
+ def max_allowed_packet_reached?(current_packet, previous_packet)
144
+ if current_packet.bytesize > max_allowed_packet
145
+ raise ActiveRecordError,
146
+ "Fixtures set is too large #{current_packet.bytesize}. Consider increasing the max_allowed_packet variable."
147
+ elsif previous_packet.nil?
148
+ true
149
+ else
150
+ (current_packet.bytesize + previous_packet.bytesize + 2) > max_allowed_packet
151
+ end
152
+ end
153
+
154
+ def max_allowed_packet
155
+ @max_allowed_packet ||= show_variable("max_allowed_packet")
156
+ end
157
+
101
158
  def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
159
+ if preventing_writes? && write_query?(sql)
160
+ raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
161
+ end
162
+
163
+ materialize_transactions
164
+
102
165
  # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
103
166
  # made since we established the connection
104
167
  @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
@@ -107,10 +170,7 @@ module ActiveRecord
107
170
 
108
171
  log(sql, name, binds, type_casted_binds) do
109
172
  if cache_stmt
110
- cache = @statements[sql] ||= {
111
- stmt: @connection.prepare(sql)
112
- }
113
- stmt = cache[:stmt]
173
+ stmt = @statements[sql] ||= @connection.prepare(sql)
114
174
  else
115
175
  stmt = @connection.prepare(sql)
116
176
  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