activerecord 4.0.4 → 4.1.16
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
@@ -13,41 +13,173 @@ module ActiveRecord
|
|
13
13
|
@config = original.config.dup
|
14
14
|
end
|
15
15
|
|
16
|
+
# Expands a connection string into a hash.
|
17
|
+
class ConnectionUrlResolver # :nodoc:
|
18
|
+
|
19
|
+
# == Example
|
20
|
+
#
|
21
|
+
# url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
|
22
|
+
# ConnectionUrlResolver.new(url).to_hash
|
23
|
+
# # => {
|
24
|
+
# "adapter" => "postgresql",
|
25
|
+
# "host" => "localhost",
|
26
|
+
# "port" => 9000,
|
27
|
+
# "database" => "foo_test",
|
28
|
+
# "username" => "foo",
|
29
|
+
# "password" => "bar",
|
30
|
+
# "pool" => "5",
|
31
|
+
# "timeout" => "3000"
|
32
|
+
# }
|
33
|
+
def initialize(url)
|
34
|
+
raise "Database URL cannot be empty" if url.blank?
|
35
|
+
@uri = URI.parse(url)
|
36
|
+
@adapter = @uri.scheme.gsub('-', '_')
|
37
|
+
@adapter = "postgresql" if @adapter == "postgres"
|
38
|
+
|
39
|
+
if @uri.opaque
|
40
|
+
@uri.opaque, @query = @uri.opaque.split('?', 2)
|
41
|
+
else
|
42
|
+
@query = @uri.query
|
43
|
+
end
|
44
|
+
@authority = url =~ %r{\A[^:]*://}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Converts the given URL to a full connection hash.
|
48
|
+
def to_hash
|
49
|
+
config = raw_config.reject { |_,value| value.blank? }
|
50
|
+
config.map { |key,value| config[key] = uri_parser.unescape(value) if value.is_a? String }
|
51
|
+
config
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def uri
|
57
|
+
@uri
|
58
|
+
end
|
59
|
+
|
60
|
+
def uri_parser
|
61
|
+
@uri_parser ||= URI::Parser.new
|
62
|
+
end
|
63
|
+
|
64
|
+
# Converts the query parameters of the URI into a hash.
|
65
|
+
#
|
66
|
+
# "localhost?pool=5&reap_frequency=2"
|
67
|
+
# # => { "pool" => "5", "reap_frequency" => "2" }
|
68
|
+
#
|
69
|
+
# returns empty hash if no query present.
|
70
|
+
#
|
71
|
+
# "localhost"
|
72
|
+
# # => {}
|
73
|
+
def query_hash
|
74
|
+
Hash[(@query || '').split("&").map { |pair| pair.split("=") }]
|
75
|
+
end
|
76
|
+
|
77
|
+
def raw_config
|
78
|
+
if uri.opaque
|
79
|
+
query_hash.merge({
|
80
|
+
"adapter" => @adapter,
|
81
|
+
"database" => uri.opaque })
|
82
|
+
else
|
83
|
+
query_hash.merge({
|
84
|
+
"adapter" => @adapter,
|
85
|
+
"username" => uri.user,
|
86
|
+
"password" => uri.password,
|
87
|
+
"port" => uri.port,
|
88
|
+
"database" => database_from_path,
|
89
|
+
"host" => uri.hostname })
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns name of the database.
|
94
|
+
# Sqlite3's handling of a leading slash is in transition as of
|
95
|
+
# Rails 4.1.
|
96
|
+
def database_from_path
|
97
|
+
if @authority && @adapter == 'sqlite3'
|
98
|
+
# 'sqlite3:///foo' is relative, for backwards compatibility.
|
99
|
+
|
100
|
+
database_name = uri.path.sub(%r{^/}, "")
|
101
|
+
|
102
|
+
msg = "Paths in SQLite3 database URLs of the form `sqlite3:///path` will be treated as absolute in Rails 4.2. " \
|
103
|
+
"Please switch to `sqlite3:#{database_name}`."
|
104
|
+
ActiveSupport::Deprecation.warn(msg)
|
105
|
+
|
106
|
+
database_name
|
107
|
+
|
108
|
+
elsif @adapter == 'sqlite3'
|
109
|
+
# 'sqlite3:/foo' is absolute, because that makes sense. The
|
110
|
+
# corresponding relative version, 'sqlite3:foo', is handled
|
111
|
+
# elsewhere, as an "opaque".
|
112
|
+
|
113
|
+
uri.path
|
114
|
+
else
|
115
|
+
# Only SQLite uses a filename as the "database" name; for
|
116
|
+
# anything else, a leading slash would be silly.
|
117
|
+
|
118
|
+
uri.path.sub(%r{^/}, "")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
16
123
|
##
|
17
|
-
# Builds a ConnectionSpecification from user input
|
124
|
+
# Builds a ConnectionSpecification from user input.
|
18
125
|
class Resolver # :nodoc:
|
19
|
-
attr_reader :
|
126
|
+
attr_reader :configurations
|
20
127
|
|
21
|
-
|
22
|
-
|
128
|
+
# Accepts a hash two layers deep, keys on the first layer represent
|
129
|
+
# environments such as "production". Keys must be strings.
|
130
|
+
def initialize(configurations)
|
23
131
|
@configurations = configurations
|
24
132
|
end
|
25
133
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
134
|
+
# Returns a hash with database connection information.
|
135
|
+
#
|
136
|
+
# == Examples
|
137
|
+
#
|
138
|
+
# Full hash Configuration.
|
139
|
+
#
|
140
|
+
# configurations = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
141
|
+
# Resolver.new(configurations).resolve(:production)
|
142
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3"}
|
143
|
+
#
|
144
|
+
# Initialized with URL configuration strings.
|
145
|
+
#
|
146
|
+
# configurations = { "production" => "postgresql://localhost/foo" }
|
147
|
+
# Resolver.new(configurations).resolve(:production)
|
148
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
149
|
+
#
|
150
|
+
def resolve(config)
|
151
|
+
if config
|
152
|
+
resolve_connection config
|
153
|
+
elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call
|
154
|
+
resolve_symbol_connection env.to_sym
|
155
|
+
else
|
156
|
+
raise AdapterNotSpecified
|
35
157
|
end
|
36
158
|
end
|
37
159
|
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
|
160
|
+
# Expands each key in @configurations hash into fully resolved hash
|
161
|
+
def resolve_all
|
162
|
+
config = configurations.dup
|
163
|
+
config.each do |key, value|
|
164
|
+
config[key] = resolve(value) if value
|
42
165
|
end
|
43
|
-
|
44
|
-
raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
|
45
|
-
|
46
|
-
resolve_hash_connection hash
|
166
|
+
config
|
47
167
|
end
|
48
168
|
|
49
|
-
|
50
|
-
|
169
|
+
# Returns an instance of ConnectionSpecification for a given adapter.
|
170
|
+
# Accepts a hash one layer deep that contains all connection information.
|
171
|
+
#
|
172
|
+
# == Example
|
173
|
+
#
|
174
|
+
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
175
|
+
# spec = Resolver.new(config).spec(:production)
|
176
|
+
# spec.adapter_method
|
177
|
+
# # => "sqlite3"
|
178
|
+
# spec.config
|
179
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
|
180
|
+
#
|
181
|
+
def spec(config)
|
182
|
+
spec = resolve(config).symbolize_keys
|
51
183
|
|
52
184
|
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
53
185
|
|
@@ -55,41 +187,97 @@ module ActiveRecord
|
|
55
187
|
begin
|
56
188
|
require path_to_adapter
|
57
189
|
rescue Gem::LoadError => e
|
58
|
-
raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile."
|
190
|
+
raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)."
|
59
191
|
rescue LoadError => e
|
60
192
|
raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
|
61
193
|
end
|
62
194
|
|
63
195
|
adapter_method = "#{spec[:adapter]}_connection"
|
64
|
-
|
65
196
|
ConnectionSpecification.new(spec, adapter_method)
|
66
197
|
end
|
67
198
|
|
68
|
-
|
69
|
-
config = URI.parse url
|
70
|
-
adapter = config.scheme
|
71
|
-
adapter = "postgresql" if adapter == "postgres"
|
72
|
-
spec = { :adapter => adapter,
|
73
|
-
:username => config.user,
|
74
|
-
:password => config.password,
|
75
|
-
:port => config.port,
|
76
|
-
:database => config.path.sub(%r{^/},""),
|
77
|
-
:host => config.host }
|
78
|
-
|
79
|
-
spec.reject!{ |_,value| value.blank? }
|
80
|
-
|
81
|
-
uri_parser = URI::Parser.new
|
199
|
+
private
|
82
200
|
|
83
|
-
|
201
|
+
# Returns fully resolved connection, accepts hash, string or symbol.
|
202
|
+
# Always returns a hash.
|
203
|
+
#
|
204
|
+
# == Examples
|
205
|
+
#
|
206
|
+
# Symbol representing current environment.
|
207
|
+
#
|
208
|
+
# Resolver.new("production" => {}).resolve_connection(:production)
|
209
|
+
# # => {}
|
210
|
+
#
|
211
|
+
# One layer deep hash of connection values.
|
212
|
+
#
|
213
|
+
# Resolver.new({}).resolve_connection("adapter" => "sqlite3")
|
214
|
+
# # => { "adapter" => "sqlite3" }
|
215
|
+
#
|
216
|
+
# Connection URL.
|
217
|
+
#
|
218
|
+
# Resolver.new({}).resolve_connection("postgresql://localhost/foo")
|
219
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
220
|
+
#
|
221
|
+
def resolve_connection(spec)
|
222
|
+
case spec
|
223
|
+
when Symbol
|
224
|
+
resolve_symbol_connection spec
|
225
|
+
when String
|
226
|
+
resolve_string_connection spec
|
227
|
+
when Hash
|
228
|
+
resolve_hash_connection spec
|
229
|
+
end
|
230
|
+
end
|
84
231
|
|
85
|
-
|
86
|
-
|
232
|
+
def resolve_string_connection(spec)
|
233
|
+
# Rails has historically accepted a string to mean either
|
234
|
+
# an environment key or a URL spec, so we have deprecated
|
235
|
+
# this ambiguous behaviour and in the future this function
|
236
|
+
# can be removed in favor of resolve_url_connection.
|
237
|
+
if configurations.key?(spec) || spec !~ /:/
|
238
|
+
ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \
|
239
|
+
"for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead"
|
240
|
+
resolve_symbol_connection(spec)
|
241
|
+
else
|
242
|
+
resolve_url_connection(spec)
|
243
|
+
end
|
244
|
+
end
|
87
245
|
|
88
|
-
|
246
|
+
# Takes the environment such as `:production` or `:development`.
|
247
|
+
# This requires that the @configurations was initialized with a key that
|
248
|
+
# matches.
|
249
|
+
#
|
250
|
+
# Resolver.new("production" => {}).resolve_symbol_connection(:production)
|
251
|
+
# # => {}
|
252
|
+
#
|
253
|
+
def resolve_symbol_connection(spec)
|
254
|
+
if config = configurations[spec.to_s]
|
255
|
+
resolve_connection(config)
|
256
|
+
else
|
257
|
+
raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
|
89
258
|
end
|
259
|
+
end
|
90
260
|
|
261
|
+
# Accepts a hash. Expands the "url" key that contains a
|
262
|
+
# URL database connection to a full connection
|
263
|
+
# hash and merges with the rest of the hash.
|
264
|
+
# Connection details inside of the "url" key win any merge conflicts
|
265
|
+
def resolve_hash_connection(spec)
|
266
|
+
if spec["url"] && spec["url"] !~ /^jdbc:/
|
267
|
+
connection_hash = resolve_string_connection(spec.delete("url"))
|
268
|
+
spec.merge!(connection_hash)
|
269
|
+
end
|
91
270
|
spec
|
92
271
|
end
|
272
|
+
|
273
|
+
# Takes a connection URL.
|
274
|
+
#
|
275
|
+
# Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
|
276
|
+
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
|
277
|
+
#
|
278
|
+
def resolve_url_connection(url)
|
279
|
+
ConnectionUrlResolver.new(url).to_hash
|
280
|
+
end
|
93
281
|
end
|
94
282
|
end
|
95
283
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
2
2
|
|
3
|
-
gem 'mysql2', '~> 0.3.
|
3
|
+
gem 'mysql2', '~> 0.3.13'
|
4
4
|
require 'mysql2'
|
5
5
|
|
6
6
|
module ActiveRecord
|
@@ -18,6 +18,12 @@ module ActiveRecord
|
|
18
18
|
client = Mysql2::Client.new(config)
|
19
19
|
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
20
20
|
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
21
|
+
rescue Mysql2::Error => error
|
22
|
+
if error.message.include?("Unknown database")
|
23
|
+
raise ActiveRecord::NoDatabaseError.new(error.message)
|
24
|
+
else
|
25
|
+
raise error
|
26
|
+
end
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
@@ -229,8 +235,7 @@ module ActiveRecord
|
|
229
235
|
|
230
236
|
alias exec_without_stmt exec_query
|
231
237
|
|
232
|
-
# Returns an
|
233
|
-
# column values as values.
|
238
|
+
# Returns an ActiveRecord::Result instance.
|
234
239
|
def select(sql, name = nil, binds = [])
|
235
240
|
exec_query(sql, name)
|
236
241
|
end
|
@@ -267,8 +272,8 @@ module ActiveRecord
|
|
267
272
|
super
|
268
273
|
end
|
269
274
|
|
270
|
-
def
|
271
|
-
@
|
275
|
+
def full_version
|
276
|
+
@full_version ||= @connection.server_info[:version]
|
272
277
|
end
|
273
278
|
|
274
279
|
def set_field_encoding field_name
|
@@ -34,6 +34,12 @@ module ActiveRecord
|
|
34
34
|
default_flags |= Mysql::CLIENT_FOUND_ROWS if Mysql.const_defined?(:CLIENT_FOUND_ROWS)
|
35
35
|
options = [host, username, password, database, port, socket, default_flags]
|
36
36
|
ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config)
|
37
|
+
rescue Mysql::Error => error
|
38
|
+
if error.message.include?("Unknown database")
|
39
|
+
raise ActiveRecord::NoDatabaseError.new(error.message)
|
40
|
+
else
|
41
|
+
raise error
|
42
|
+
end
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
@@ -51,7 +57,7 @@ module ActiveRecord
|
|
51
57
|
# * <tt>:database</tt> - The name of the database. No default, must be provided.
|
52
58
|
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
|
53
59
|
# * <tt>:reconnect</tt> - Defaults to false (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/auto-reconnect.html).
|
54
|
-
# * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/
|
60
|
+
# * <tt>:strict</tt> - Defaults to true. Enable STRICT_ALL_TABLES. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html)
|
55
61
|
# * <tt>:variables</tt> - (Optional) A hash session variables to send as `SET @@SESSION.key = value` on each database connection. Use the value `:default` to set a variable to its DEFAULT value. (See MySQL documentation: http://dev.mysql.com/doc/refman/5.0/en/set-statement.html).
|
56
62
|
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
|
57
63
|
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
|
@@ -160,12 +166,6 @@ module ActiveRecord
|
|
160
166
|
|
161
167
|
# QUOTING ==================================================
|
162
168
|
|
163
|
-
def type_cast(value, column)
|
164
|
-
return super unless value == true || value == false
|
165
|
-
|
166
|
-
value ? 1 : 0
|
167
|
-
end
|
168
|
-
|
169
169
|
def quote_string(string) #:nodoc:
|
170
170
|
@connection.quote(string)
|
171
171
|
end
|
@@ -425,14 +425,19 @@ module ActiveRecord
|
|
425
425
|
|
426
426
|
if result
|
427
427
|
types = {}
|
428
|
+
fields = []
|
428
429
|
result.fetch_fields.each { |field|
|
430
|
+
field_name = field.name
|
431
|
+
fields << field_name
|
432
|
+
|
429
433
|
if field.decimals > 0
|
430
|
-
types[
|
434
|
+
types[field_name] = Fields::Decimal.new
|
431
435
|
else
|
432
|
-
types[
|
436
|
+
types[field_name] = Fields.find_type field
|
433
437
|
end
|
434
438
|
}
|
435
|
-
|
439
|
+
|
440
|
+
result_set = ActiveRecord::Result.new(fields, result.to_a, types)
|
436
441
|
result.free
|
437
442
|
else
|
438
443
|
result_set = ActiveRecord::Result.new([], [])
|
@@ -468,15 +473,17 @@ module ActiveRecord
|
|
468
473
|
|
469
474
|
def begin_db_transaction #:nodoc:
|
470
475
|
exec_query "BEGIN"
|
471
|
-
rescue Mysql::Error
|
472
|
-
# Transactions aren't supported
|
473
476
|
end
|
474
477
|
|
475
478
|
private
|
476
479
|
|
477
480
|
def exec_stmt(sql, name, binds)
|
478
481
|
cache = {}
|
479
|
-
|
482
|
+
type_casted_binds = binds.map { |col, val|
|
483
|
+
[col, type_cast(val, col)]
|
484
|
+
}
|
485
|
+
|
486
|
+
log(sql, name, type_casted_binds) do
|
480
487
|
if binds.empty?
|
481
488
|
stmt = @connection.prepare(sql)
|
482
489
|
else
|
@@ -487,7 +494,7 @@ module ActiveRecord
|
|
487
494
|
end
|
488
495
|
|
489
496
|
begin
|
490
|
-
stmt.execute(*
|
497
|
+
stmt.execute(*type_casted_binds.map { |_, val| val })
|
491
498
|
rescue Mysql::Error => e
|
492
499
|
# Older versions of MySQL leave the prepared statement in a bad
|
493
500
|
# place when an error occurs. To support older mysql versions, we
|
@@ -551,9 +558,9 @@ module ActiveRecord
|
|
551
558
|
rows
|
552
559
|
end
|
553
560
|
|
554
|
-
# Returns the version of the connected MySQL server.
|
555
|
-
def
|
556
|
-
@
|
561
|
+
# Returns the full version of the connected MySQL server.
|
562
|
+
def full_version
|
563
|
+
@full_version ||= @connection.server_info
|
557
564
|
end
|
558
565
|
|
559
566
|
def set_field_encoding field_name
|
@@ -2,6 +2,13 @@ module ActiveRecord
|
|
2
2
|
module ConnectionAdapters
|
3
3
|
class PostgreSQLColumn < Column
|
4
4
|
module ArrayParser
|
5
|
+
|
6
|
+
DOUBLE_QUOTE = '"'
|
7
|
+
BACKSLASH = "\\"
|
8
|
+
COMMA = ','
|
9
|
+
BRACKET_OPEN = '{'
|
10
|
+
BRACKET_CLOSE = '}'
|
11
|
+
|
5
12
|
private
|
6
13
|
# Loads pg_array_parser if available. String parsing can be
|
7
14
|
# performed quicker by a native extension, which will not create
|
@@ -12,18 +19,18 @@ module ActiveRecord
|
|
12
19
|
include PgArrayParser
|
13
20
|
rescue LoadError
|
14
21
|
def parse_pg_array(string)
|
15
|
-
parse_data(string
|
22
|
+
parse_data(string)
|
16
23
|
end
|
17
24
|
end
|
18
25
|
|
19
|
-
def parse_data(string
|
20
|
-
local_index =
|
26
|
+
def parse_data(string)
|
27
|
+
local_index = 0
|
21
28
|
array = []
|
22
29
|
while(local_index < string.length)
|
23
30
|
case string[local_index]
|
24
|
-
when
|
31
|
+
when BRACKET_OPEN
|
25
32
|
local_index,array = parse_array_contents(array, string, local_index + 1)
|
26
|
-
when
|
33
|
+
when BRACKET_CLOSE
|
27
34
|
return array
|
28
35
|
end
|
29
36
|
local_index += 1
|
@@ -33,9 +40,9 @@ module ActiveRecord
|
|
33
40
|
end
|
34
41
|
|
35
42
|
def parse_array_contents(array, string, index)
|
36
|
-
is_escaping
|
37
|
-
is_quoted
|
38
|
-
was_quoted
|
43
|
+
is_escaping = false
|
44
|
+
is_quoted = false
|
45
|
+
was_quoted = false
|
39
46
|
current_item = ''
|
40
47
|
|
41
48
|
local_index = index
|
@@ -47,29 +54,29 @@ module ActiveRecord
|
|
47
54
|
else
|
48
55
|
if is_quoted
|
49
56
|
case token
|
50
|
-
when
|
57
|
+
when DOUBLE_QUOTE
|
51
58
|
is_quoted = false
|
52
59
|
was_quoted = true
|
53
|
-
when
|
60
|
+
when BACKSLASH
|
54
61
|
is_escaping = true
|
55
62
|
else
|
56
63
|
current_item << token
|
57
64
|
end
|
58
65
|
else
|
59
66
|
case token
|
60
|
-
when
|
67
|
+
when BACKSLASH
|
61
68
|
is_escaping = true
|
62
|
-
when
|
69
|
+
when COMMA
|
63
70
|
add_item_to_array(array, current_item, was_quoted)
|
64
71
|
current_item = ''
|
65
72
|
was_quoted = false
|
66
|
-
when
|
73
|
+
when DOUBLE_QUOTE
|
67
74
|
is_quoted = true
|
68
|
-
when
|
75
|
+
when BRACKET_OPEN
|
69
76
|
internal_items = []
|
70
77
|
local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1)
|
71
78
|
array.push(internal_items)
|
72
|
-
when
|
79
|
+
when BRACKET_CLOSE
|
73
80
|
add_item_to_array(array, current_item, was_quoted)
|
74
81
|
return local_index,array
|
75
82
|
else
|
@@ -17,8 +17,8 @@ module ActiveRecord
|
|
17
17
|
return string unless String === string
|
18
18
|
|
19
19
|
case string
|
20
|
-
when 'infinity';
|
21
|
-
when '-infinity'; -
|
20
|
+
when 'infinity'; Float::INFINITY
|
21
|
+
when '-infinity'; -Float::INFINITY
|
22
22
|
when / BC$/
|
23
23
|
super("-" + string.sub(/ BC$/, ""))
|
24
24
|
else
|
@@ -67,7 +67,7 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
def array_to_string(value, column, adapter
|
70
|
+
def array_to_string(value, column, adapter)
|
71
71
|
casted_values = value.map do |val|
|
72
72
|
if String === val
|
73
73
|
if val == "NULL"
|
@@ -119,7 +119,7 @@ module ActiveRecord
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def string_to_array(string, oid)
|
122
|
-
parse_pg_array(string).map{|val| oid
|
122
|
+
parse_pg_array(string).map {|val| type_cast_array(oid, val)}
|
123
123
|
end
|
124
124
|
|
125
125
|
private
|
@@ -154,6 +154,14 @@ module ActiveRecord
|
|
154
154
|
"\"#{value}\""
|
155
155
|
end
|
156
156
|
end
|
157
|
+
|
158
|
+
def type_cast_array(oid, value)
|
159
|
+
if ::Array === value
|
160
|
+
value.map {|item| type_cast_array(oid, item)}
|
161
|
+
else
|
162
|
+
oid.type_cast value
|
163
|
+
end
|
164
|
+
end
|
157
165
|
end
|
158
166
|
end
|
159
167
|
end
|
@@ -134,35 +134,28 @@ module ActiveRecord
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def exec_query(sql, name = 'SQL', binds = [])
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
types[fname] = OID::TYPE_MAP.fetch(ftype, fmod) { |oid, mod|
|
147
|
-
warn "unknown OID: #{fname}(#{oid}) (#{sql})"
|
148
|
-
OID::Identity.new
|
149
|
-
}
|
150
|
-
end
|
151
|
-
|
152
|
-
ret = ActiveRecord::Result.new(fields, result.values, types)
|
153
|
-
result.clear
|
154
|
-
return ret
|
137
|
+
result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
|
138
|
+
exec_cache(sql, name, binds)
|
139
|
+
|
140
|
+
types = {}
|
141
|
+
fields = result.fields
|
142
|
+
fields.each_with_index do |fname, i|
|
143
|
+
ftype = result.ftype i
|
144
|
+
fmod = result.fmod i
|
145
|
+
types[fname] = get_oid_type(ftype, fmod, fname)
|
155
146
|
end
|
147
|
+
|
148
|
+
ret = ActiveRecord::Result.new(fields, result.values, types)
|
149
|
+
result.clear
|
150
|
+
return ret
|
156
151
|
end
|
157
152
|
|
158
153
|
def exec_delete(sql, name = 'SQL', binds = [])
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
affected
|
165
|
-
end
|
154
|
+
result = without_prepared_statement?(binds) ? exec_no_cache(sql, name, binds) :
|
155
|
+
exec_cache(sql, name, binds)
|
156
|
+
affected = result.cmd_tuples
|
157
|
+
result.clear
|
158
|
+
affected
|
166
159
|
end
|
167
160
|
alias :exec_update :exec_delete
|
168
161
|
|
@@ -218,25 +211,6 @@ module ActiveRecord
|
|
218
211
|
def rollback_db_transaction
|
219
212
|
execute "ROLLBACK"
|
220
213
|
end
|
221
|
-
|
222
|
-
def outside_transaction?
|
223
|
-
message = "#outside_transaction? is deprecated. This method was only really used " \
|
224
|
-
"internally, but you can use #transaction_open? instead."
|
225
|
-
ActiveSupport::Deprecation.warn message
|
226
|
-
@connection.transaction_status == PGconn::PQTRANS_IDLE
|
227
|
-
end
|
228
|
-
|
229
|
-
def create_savepoint
|
230
|
-
execute("SAVEPOINT #{current_savepoint_name}")
|
231
|
-
end
|
232
|
-
|
233
|
-
def rollback_to_savepoint
|
234
|
-
execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
|
235
|
-
end
|
236
|
-
|
237
|
-
def release_savepoint
|
238
|
-
execute("RELEASE SAVEPOINT #{current_savepoint_name}")
|
239
|
-
end
|
240
214
|
end
|
241
215
|
end
|
242
216
|
end
|