activerecord 5.0.7.2 → 5.1.0.beta1

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 (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -13,7 +13,7 @@ module ActiveRecord
13
13
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
14
14
  # +sql_type_metadata+ is various information about the type of the column
15
15
  # +null+ determines if this column allows +NULL+ values.
16
- def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
16
+ def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
17
17
  @name = name.freeze
18
18
  @table_name = table_name
19
19
  @sql_type_metadata = sql_type_metadata
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  end
30
30
 
31
31
  def bigint?
32
- /\Abigint\b/ === sql_type
32
+ /\Abigint\b/.match?(sql_type)
33
33
  end
34
34
 
35
35
  # Returns the human name of the column name.
@@ -40,6 +40,28 @@ module ActiveRecord
40
40
  Base.human_attribute_name(@name)
41
41
  end
42
42
 
43
+ def init_with(coder)
44
+ @name = coder["name"]
45
+ @table_name = coder["table_name"]
46
+ @sql_type_metadata = coder["sql_type_metadata"]
47
+ @null = coder["null"]
48
+ @default = coder["default"]
49
+ @default_function = coder["default_function"]
50
+ @collation = coder["collation"]
51
+ @comment = coder["comment"]
52
+ end
53
+
54
+ def encode_with(coder)
55
+ coder["name"] = @name
56
+ coder["table_name"] = @table_name
57
+ coder["sql_type_metadata"] = @sql_type_metadata
58
+ coder["null"] = @null
59
+ coder["default"] = @default
60
+ coder["default_function"] = @default_function
61
+ coder["collation"] = @collation
62
+ coder["comment"] = @comment
63
+ end
64
+
43
65
  def ==(other)
44
66
  other.is_a?(Column) &&
45
67
  attributes_for_hash == other.attributes_for_hash
@@ -52,9 +74,9 @@ module ActiveRecord
52
74
 
53
75
  protected
54
76
 
55
- def attributes_for_hash
56
- [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
57
- end
77
+ def attributes_for_hash
78
+ [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
79
+ end
58
80
  end
59
81
 
60
82
  class NullColumn < Column
@@ -1,4 +1,4 @@
1
- require 'uri'
1
+ require "uri"
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
@@ -13,9 +13,12 @@ module ActiveRecord
13
13
  @config = original.config.dup
14
14
  end
15
15
 
16
+ def to_hash
17
+ @config.merge(name: @name)
18
+ end
19
+
16
20
  # Expands a connection string into a hash.
17
21
  class ConnectionUrlResolver # :nodoc:
18
-
19
22
  # == Example
20
23
  #
21
24
  # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
@@ -33,11 +36,11 @@ module ActiveRecord
33
36
  def initialize(url)
34
37
  raise "Database URL cannot be empty" if url.blank?
35
38
  @uri = uri_parser.parse(url)
36
- @adapter = @uri.scheme && @uri.scheme.tr('-', '_')
39
+ @adapter = @uri.scheme && @uri.scheme.tr("-", "_")
37
40
  @adapter = "postgresql" if @adapter == "postgres"
38
41
 
39
42
  if @uri.opaque
40
- @uri.opaque, @query = @uri.opaque.split('?', 2)
43
+ @uri.opaque, @query = @uri.opaque.split("?", 2)
41
44
  else
42
45
  @query = @uri.query
43
46
  end
@@ -45,65 +48,65 @@ module ActiveRecord
45
48
 
46
49
  # Converts the given URL to a full connection hash.
47
50
  def to_hash
48
- config = raw_config.reject { |_,value| value.blank? }
49
- config.map { |key,value| config[key] = uri_parser.unescape(value) if value.is_a? String }
51
+ config = raw_config.reject { |_, value| value.blank? }
52
+ config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
50
53
  config
51
54
  end
52
55
 
53
56
  private
54
57
 
55
- def uri
56
- @uri
57
- end
58
+ def uri
59
+ @uri
60
+ end
58
61
 
59
- def uri_parser
60
- @uri_parser ||= URI::Parser.new
61
- end
62
+ def uri_parser
63
+ @uri_parser ||= URI::Parser.new
64
+ end
62
65
 
63
- # Converts the query parameters of the URI into a hash.
64
- #
65
- # "localhost?pool=5&reaping_frequency=2"
66
- # # => { "pool" => "5", "reaping_frequency" => "2" }
67
- #
68
- # returns empty hash if no query present.
69
- #
70
- # "localhost"
71
- # # => {}
72
- def query_hash
73
- Hash[(@query || '').split("&").map { |pair| pair.split("=") }]
74
- end
66
+ # Converts the query parameters of the URI into a hash.
67
+ #
68
+ # "localhost?pool=5&reaping_frequency=2"
69
+ # # => { "pool" => "5", "reaping_frequency" => "2" }
70
+ #
71
+ # returns empty hash if no query present.
72
+ #
73
+ # "localhost"
74
+ # # => {}
75
+ def query_hash
76
+ Hash[(@query || "").split("&").map { |pair| pair.split("=") }]
77
+ end
75
78
 
76
- def raw_config
77
- if uri.opaque
78
- query_hash.merge({
79
- "adapter" => @adapter,
80
- "database" => uri.opaque })
81
- else
82
- query_hash.merge({
83
- "adapter" => @adapter,
84
- "username" => uri.user,
85
- "password" => uri.password,
86
- "port" => uri.port,
87
- "database" => database_from_path,
88
- "host" => uri.hostname })
79
+ def raw_config
80
+ if uri.opaque
81
+ query_hash.merge(
82
+ "adapter" => @adapter,
83
+ "database" => uri.opaque)
84
+ else
85
+ query_hash.merge(
86
+ "adapter" => @adapter,
87
+ "username" => uri.user,
88
+ "password" => uri.password,
89
+ "port" => uri.port,
90
+ "database" => database_from_path,
91
+ "host" => uri.hostname)
92
+ end
89
93
  end
90
- end
91
94
 
92
- # Returns name of the database.
93
- def database_from_path
94
- if @adapter == 'sqlite3'
95
- # 'sqlite3:/foo' is absolute, because that makes sense. The
96
- # corresponding relative version, 'sqlite3:foo', is handled
97
- # elsewhere, as an "opaque".
95
+ # Returns name of the database.
96
+ def database_from_path
97
+ if @adapter == "sqlite3"
98
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
99
+ # corresponding relative version, 'sqlite3:foo', is handled
100
+ # elsewhere, as an "opaque".
98
101
 
99
- uri.path
100
- else
101
- # Only SQLite uses a filename as the "database" name; for
102
- # anything else, a leading slash would be silly.
102
+ uri.path
103
+ else
104
+ # Only SQLite uses a filename as the "database" name; for
105
+ # anything else, a leading slash would be silly.
103
106
 
104
- uri.path.sub(%r{^/}, "")
107
+ uri.path.sub(%r{^/}, "")
108
+ end
105
109
  end
106
- end
107
110
  end
108
111
 
109
112
  ##
@@ -146,9 +149,18 @@ module ActiveRecord
146
149
  # Expands each key in @configurations hash into fully resolved hash
147
150
  def resolve_all
148
151
  config = configurations.dup
152
+
153
+ if env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
154
+ env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
155
+ end
156
+
157
+ config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
158
+ config.merge! env_config if env_config
159
+
149
160
  config.each do |key, value|
150
161
  config[key] = resolve(value) if value
151
162
  end
163
+
152
164
  config
153
165
  end
154
166
 
@@ -164,7 +176,7 @@ module ActiveRecord
164
176
  # spec.config
165
177
  # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
166
178
  #
167
- def spec(config, name = nil)
179
+ def spec(config)
168
180
  spec = resolve(config).symbolize_keys
169
181
 
170
182
  raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
@@ -180,83 +192,81 @@ module ActiveRecord
180
192
 
181
193
  adapter_method = "#{spec[:adapter]}_connection"
182
194
 
183
- name ||=
184
- if config.is_a?(Symbol)
185
- config.to_s
186
- else
187
- "primary"
188
- end
189
- ConnectionSpecification.new(name, spec, adapter_method)
195
+ unless ActiveRecord::Base.respond_to?(adapter_method)
196
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
197
+ end
198
+
199
+ ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method)
190
200
  end
191
201
 
192
202
  private
193
203
 
194
- # Returns fully resolved connection, accepts hash, string or symbol.
195
- # Always returns a hash.
196
- #
197
- # == Examples
198
- #
199
- # Symbol representing current environment.
200
- #
201
- # Resolver.new("production" => {}).resolve_connection(:production)
202
- # # => {}
203
- #
204
- # One layer deep hash of connection values.
205
- #
206
- # Resolver.new({}).resolve_connection("adapter" => "sqlite3")
207
- # # => { "adapter" => "sqlite3" }
208
- #
209
- # Connection URL.
210
- #
211
- # Resolver.new({}).resolve_connection("postgresql://localhost/foo")
212
- # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
213
- #
214
- def resolve_connection(spec)
215
- case spec
216
- when Symbol
217
- resolve_symbol_connection spec
218
- when String
219
- resolve_url_connection spec
220
- when Hash
221
- resolve_hash_connection spec
204
+ # Returns fully resolved connection, accepts hash, string or symbol.
205
+ # Always returns a hash.
206
+ #
207
+ # == Examples
208
+ #
209
+ # Symbol representing current environment.
210
+ #
211
+ # Resolver.new("production" => {}).resolve_connection(:production)
212
+ # # => {}
213
+ #
214
+ # One layer deep hash of connection values.
215
+ #
216
+ # Resolver.new({}).resolve_connection("adapter" => "sqlite3")
217
+ # # => { "adapter" => "sqlite3" }
218
+ #
219
+ # Connection URL.
220
+ #
221
+ # Resolver.new({}).resolve_connection("postgresql://localhost/foo")
222
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
223
+ #
224
+ def resolve_connection(spec)
225
+ case spec
226
+ when Symbol
227
+ resolve_symbol_connection spec
228
+ when String
229
+ resolve_url_connection spec
230
+ when Hash
231
+ resolve_hash_connection spec
232
+ end
222
233
  end
223
- end
224
234
 
225
- # Takes the environment such as +:production+ or +:development+.
226
- # This requires that the @configurations was initialized with a key that
227
- # matches.
228
- #
229
- # Resolver.new("production" => {}).resolve_symbol_connection(:production)
230
- # # => {}
231
- #
232
- def resolve_symbol_connection(spec)
233
- if config = configurations[spec.to_s]
234
- resolve_connection(config)
235
- else
236
- raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
235
+ # Takes the environment such as +:production+ or +:development+.
236
+ # This requires that the @configurations was initialized with a key that
237
+ # matches.
238
+ #
239
+ # Resolver.new("production" => {}).resolve_symbol_connection(:production)
240
+ # # => {}
241
+ #
242
+ def resolve_symbol_connection(spec)
243
+ if config = configurations[spec.to_s]
244
+ resolve_connection(config).merge("name" => spec.to_s)
245
+ else
246
+ raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
247
+ end
237
248
  end
238
- end
239
249
 
240
- # Accepts a hash. Expands the "url" key that contains a
241
- # URL database connection to a full connection
242
- # hash and merges with the rest of the hash.
243
- # Connection details inside of the "url" key win any merge conflicts
244
- def resolve_hash_connection(spec)
245
- if spec["url"] && spec["url"] !~ /^jdbc:/
246
- connection_hash = resolve_url_connection(spec.delete("url"))
247
- spec.merge!(connection_hash)
250
+ # Accepts a hash. Expands the "url" key that contains a
251
+ # URL database connection to a full connection
252
+ # hash and merges with the rest of the hash.
253
+ # Connection details inside of the "url" key win any merge conflicts
254
+ def resolve_hash_connection(spec)
255
+ if spec["url"] && spec["url"] !~ /^jdbc:/
256
+ connection_hash = resolve_url_connection(spec.delete("url"))
257
+ spec.merge!(connection_hash)
258
+ end
259
+ spec
248
260
  end
249
- spec
250
- end
251
261
 
252
- # Takes a connection URL.
253
- #
254
- # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
255
- # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
256
- #
257
- def resolve_url_connection(url)
258
- ConnectionUrlResolver.new(url).to_hash
259
- end
262
+ # Takes a connection URL.
263
+ #
264
+ # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
265
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
266
+ #
267
+ def resolve_url_connection(url)
268
+ ConnectionUrlResolver.new(url).to_hash
269
+ end
260
270
  end
261
271
  end
262
272
  end
@@ -2,47 +2,22 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
4
  class Column < ConnectionAdapters::Column # :nodoc:
5
- delegate :strict, :extra, to: :sql_type_metadata, allow_nil: true
6
-
7
- def initialize(*)
8
- super
9
- assert_valid_default
10
- extract_default
11
- end
12
-
13
- def has_default?
14
- return false if blob_or_text_column? # MySQL forbids defaults on blob and text columns
15
- super
16
- end
17
-
18
- def blob_or_text_column?
19
- /\A(?:tiny|medium|long)?blob\b/ === sql_type || type == :text
20
- end
5
+ delegate :extra, to: :sql_type_metadata, allow_nil: true
21
6
 
22
7
  def unsigned?
23
- /\A(?:enum|set)\b/ !~ sql_type && /\bunsigned\b/ === sql_type
8
+ /\bunsigned(?: zerofill)?\z/.match?(sql_type)
24
9
  end
25
10
 
26
11
  def case_sensitive?
27
- collation && collation !~ /_ci\z/
12
+ collation && !/_ci\z/.match?(collation)
28
13
  end
29
14
 
30
15
  def auto_increment?
31
- extra == 'auto_increment'
32
- end
33
-
34
- private
35
-
36
- def extract_default
37
- if blob_or_text_column?
38
- @default = null || strict ? nil : ''
39
- end
16
+ extra == "auto_increment"
40
17
  end
41
18
 
42
- def assert_valid_default
43
- if blob_or_text_column? && default.present?
44
- raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
45
- end
19
+ def virtual?
20
+ /\b(?:VIRTUAL|STORED|PERSISTENT)\b/.match?(extra)
46
21
  end
47
22
  end
48
23
  end
@@ -3,7 +3,7 @@ module ActiveRecord
3
3
  module MySQL
4
4
  module DatabaseStatements
5
5
  # Returns an ActiveRecord::Result instance.
6
- def select_all(arel, name = nil, binds = [], preparable: nil)
6
+ def select_all(arel, name = nil, binds = [], preparable: nil) # :nodoc:
7
7
  result = if ExplainRegistry.collect? && prepared_statements
8
8
  unprepared_statement { super }
9
9
  else
@@ -15,8 +15,8 @@ module ActiveRecord
15
15
 
16
16
  # Returns an array of arrays containing the field values.
17
17
  # Order is the same as that returned by +columns+.
18
- def select_rows(sql, name = nil, binds = [])
19
- select_result(sql, name, binds) do |result|
18
+ def select_rows(arel, name = nil, binds = []) # :nodoc:
19
+ select_result(arel, name, binds) do |result|
20
20
  @connection.next_result while @connection.more_results?
21
21
  result.to_a
22
22
  end
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  super
32
32
  end
33
33
 
34
- def exec_query(sql, name = 'SQL', binds = [], prepare: false)
34
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
35
35
  if without_prepared_statement?(binds)
36
36
  execute_and_free(sql, name) do |result|
37
37
  ActiveRecord::Result.new(result.fields, result.to_a) if result
@@ -43,7 +43,7 @@ module ActiveRecord
43
43
  end
44
44
  end
45
45
 
46
- def exec_delete(sql, name, binds)
46
+ def exec_delete(sql, name = nil, binds = [])
47
47
  if without_prepared_statement?(binds)
48
48
  execute_and_free(sql, name) { @connection.affected_rows }
49
49
  else
@@ -52,56 +52,58 @@ module ActiveRecord
52
52
  end
53
53
  alias :exec_update :exec_delete
54
54
 
55
- protected
56
-
57
- def last_inserted_id(result)
58
- @connection.last_id
59
- end
60
-
61
55
  private
62
56
 
63
- def select_result(sql, name = nil, binds = [])
64
- if without_prepared_statement?(binds)
65
- execute_and_free(sql, name) { |result| yield result }
66
- else
67
- exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
57
+ def last_inserted_id(result)
58
+ @connection.last_id
68
59
  end
69
- end
70
-
71
- def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
72
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
73
- # made since we established the connection
74
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
75
60
 
76
- type_casted_binds = type_casted_binds(binds)
77
-
78
- log(sql, name, binds, type_casted_binds) do
79
- if cache_stmt
80
- cache = @statements[sql] ||= {
81
- stmt: @connection.prepare(sql)
82
- }
83
- stmt = cache[:stmt]
61
+ def select_result(arel, name, binds)
62
+ arel, binds = binds_from_relation(arel, binds)
63
+ sql = to_sql(arel, binds)
64
+ if without_prepared_statement?(binds)
65
+ execute_and_free(sql, name) { |result| yield result }
84
66
  else
85
- stmt = @connection.prepare(sql)
67
+ exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
86
68
  end
69
+ end
70
+
71
+ def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
72
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
73
+ # made since we established the connection
74
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
87
75
 
88
- begin
89
- result = stmt.execute(*type_casted_binds)
90
- rescue Mysql2::Error => e
76
+ type_casted_binds = type_casted_binds(binds)
77
+
78
+ log(sql, name, binds, type_casted_binds) do
91
79
  if cache_stmt
92
- @statements.delete(sql)
80
+ cache = @statements[sql] ||= {
81
+ stmt: @connection.prepare(sql)
82
+ }
83
+ stmt = cache[:stmt]
93
84
  else
94
- stmt.close
85
+ stmt = @connection.prepare(sql)
95
86
  end
96
- raise e
97
- end
98
87
 
99
- ret = yield stmt, result
100
- result.free if result
101
- stmt.close unless cache_stmt
102
- ret
88
+ begin
89
+ result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
90
+ stmt.execute(*type_casted_binds)
91
+ end
92
+ rescue Mysql2::Error => e
93
+ if cache_stmt
94
+ @statements.delete(sql)
95
+ else
96
+ stmt.close
97
+ end
98
+ raise e
99
+ end
100
+
101
+ ret = yield stmt, result
102
+ result.free if result
103
+ stmt.close unless cache_stmt
104
+ ret
105
+ end
103
106
  end
104
- end
105
107
  end
106
108
  end
107
109
  end