activerecord 5.0.7 → 5.1.7

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 (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  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/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  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 +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  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 -19
  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/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  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 +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -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
@@ -13,13 +13,8 @@ module ActiveRecord
13
13
  result
14
14
  end
15
15
 
16
- # Returns an array of arrays containing the field values.
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|
20
- @connection.next_result while @connection.more_results?
21
- result.to_a
22
- end
16
+ def query(sql, name = nil) # :nodoc:
17
+ execute(sql, name).to_a
23
18
  end
24
19
 
25
20
  # Executes the SQL statement in the context of this connection.
@@ -31,7 +26,7 @@ module ActiveRecord
31
26
  super
32
27
  end
33
28
 
34
- def exec_query(sql, name = 'SQL', binds = [], prepare: false)
29
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
35
30
  if without_prepared_statement?(binds)
36
31
  execute_and_free(sql, name) do |result|
37
32
  ActiveRecord::Result.new(result.fields, result.to_a) if result
@@ -43,7 +38,7 @@ module ActiveRecord
43
38
  end
44
39
  end
45
40
 
46
- def exec_delete(sql, name, binds)
41
+ def exec_delete(sql, name = nil, binds = [])
47
42
  if without_prepared_statement?(binds)
48
43
  execute_and_free(sql, name) { @connection.affected_rows }
49
44
  else
@@ -52,56 +47,48 @@ module ActiveRecord
52
47
  end
53
48
  alias :exec_update :exec_delete
54
49
 
55
- protected
56
-
57
- def last_inserted_id(result)
58
- @connection.last_id
59
- end
60
-
61
50
  private
62
51
 
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 }
52
+ def last_inserted_id(result)
53
+ @connection.last_id
68
54
  end
69
- end
70
55
 
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
-
76
- type_casted_binds = type_casted_binds(binds)
56
+ def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
57
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
58
+ # made since we established the connection
59
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
77
60
 
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]
84
- else
85
- stmt = @connection.prepare(sql)
86
- end
61
+ type_casted_binds = type_casted_binds(binds)
87
62
 
88
- begin
89
- result = stmt.execute(*type_casted_binds)
90
- rescue Mysql2::Error => e
63
+ log(sql, name, binds, type_casted_binds) do
91
64
  if cache_stmt
92
- @statements.delete(sql)
65
+ cache = @statements[sql] ||= {
66
+ stmt: @connection.prepare(sql)
67
+ }
68
+ stmt = cache[:stmt]
93
69
  else
94
- stmt.close
70
+ stmt = @connection.prepare(sql)
95
71
  end
96
- raise e
97
- end
98
72
 
99
- ret = yield stmt, result
100
- result.free if result
101
- stmt.close unless cache_stmt
102
- ret
73
+ begin
74
+ result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
75
+ stmt.execute(*type_casted_binds)
76
+ end
77
+ rescue Mysql2::Error => e
78
+ if cache_stmt
79
+ @statements.delete(sql)
80
+ else
81
+ stmt.close
82
+ end
83
+ raise e
84
+ end
85
+
86
+ ret = yield stmt, result
87
+ result.free if result
88
+ stmt.close unless cache_stmt
89
+ ret
90
+ end
103
91
  end
104
- end
105
92
  end
106
93
  end
107
94
  end
@@ -36,34 +36,34 @@ module ActiveRecord
36
36
 
37
37
  private
38
38
 
39
- def compute_column_widths(result)
40
- [].tap do |widths|
41
- result.columns.each_with_index do |column, i|
42
- cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
43
- widths << cells_in_column.map(&:length).max
39
+ def compute_column_widths(result)
40
+ [].tap do |widths|
41
+ result.columns.each_with_index do |column, i|
42
+ cells_in_column = [column] + result.rows.map { |r| r[i].nil? ? "NULL" : r[i].to_s }
43
+ widths << cells_in_column.map(&:length).max
44
+ end
44
45
  end
45
46
  end
46
- end
47
47
 
48
- def build_separator(widths)
49
- padding = 1
50
- '+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
51
- end
48
+ def build_separator(widths)
49
+ padding = 1
50
+ "+" + widths.map { |w| "-" * (w + (padding * 2)) }.join("+") + "+"
51
+ end
52
52
 
53
- def build_cells(items, widths)
54
- cells = []
55
- items.each_with_index do |item, i|
56
- item = 'NULL' if item.nil?
57
- justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
58
- cells << item.to_s.send(justifier, widths[i])
53
+ def build_cells(items, widths)
54
+ cells = []
55
+ items.each_with_index do |item, i|
56
+ item = "NULL" if item.nil?
57
+ justifier = item.is_a?(Numeric) ? "rjust" : "ljust"
58
+ cells << item.to_s.send(justifier, widths[i])
59
+ end
60
+ "| " + cells.join(" | ") + " |"
59
61
  end
60
- '| ' + cells.join(' | ') + ' |'
61
- end
62
62
 
63
- def build_footer(nrows, elapsed)
64
- rows_label = nrows == 1 ? 'row' : 'rows'
65
- "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
66
- end
63
+ def build_footer(nrows, elapsed)
64
+ rows_label = nrows == 1 ? "row" : "rows"
65
+ "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
66
+ end
67
67
  end
68
68
  end
69
69
  end
@@ -2,14 +2,14 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module MySQL
4
4
  module Quoting # :nodoc:
5
- QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
5
+ QUOTED_TRUE, QUOTED_FALSE = "1".freeze, "0".freeze
6
6
 
7
7
  def quote_column_name(name)
8
- @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
8
+ @quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`".freeze
9
9
  end
10
10
 
11
11
  def quote_table_name(name)
12
- @quoted_table_names[name] ||= super.gsub('.', '`.`')
12
+ @quoted_table_names[name] ||= super.gsub(".", "`.`").freeze
13
13
  end
14
14
 
15
15
  def quoted_true
@@ -32,18 +32,12 @@ module ActiveRecord
32
32
  if supports_datetime_with_precision?
33
33
  super
34
34
  else
35
- super.sub(/\.\d{6}\z/, '')
35
+ super.sub(/\.\d{6}\z/, "")
36
36
  end
37
37
  end
38
38
 
39
- private
40
-
41
- def _quote(value)
42
- if value.is_a?(Type::Binary::Data)
43
- "x'#{value.hex}'"
44
- else
45
- super
46
- end
39
+ def quoted_binary(value)
40
+ "x'#{value.hex}'"
47
41
  end
48
42
  end
49
43
  end