activerecord 3.2.22.4 → 4.0.13
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 +2799 -617
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -32
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/association_relation.rb +22 -0
- data/lib/active_record/associations/alias_tracker.rb +4 -2
- data/lib/active_record/associations/association.rb +60 -46
- data/lib/active_record/associations/association_scope.rb +46 -40
- data/lib/active_record/associations/belongs_to_association.rb +17 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +73 -56
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +130 -96
- data/lib/active_record/associations/collection_proxy.rb +916 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
- data/lib/active_record/associations/has_many_association.rb +35 -8
- data/lib/active_record/associations/has_many_through_association.rb +37 -17
- data/lib/active_record/associations/has_one_association.rb +42 -19
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
- data/lib/active_record/associations/join_dependency.rb +30 -9
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/preloader.rb +20 -43
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +223 -282
- data/lib/active_record/attribute_assignment.rb +134 -154
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +36 -29
- data/lib/active_record/attribute_methods/primary_key.rb +45 -31
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +67 -90
- data/lib/active_record/attribute_methods/serialization.rb +133 -70
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
- data/lib/active_record/attribute_methods/write.rb +34 -39
- data/lib/active_record/attribute_methods.rb +268 -108
- data/lib/active_record/autosave_association.rb +80 -73
- data/lib/active_record/base.rb +54 -451
- data/lib/active_record/callbacks.rb +60 -22
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
- data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
- data/lib/active_record/connection_adapters/column.rb +67 -36
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
- data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
- data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +472 -0
- data/lib/active_record/counter_cache.rb +107 -108
- data/lib/active_record/dynamic_matchers.rb +115 -63
- data/lib/active_record/errors.rb +36 -18
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +8 -4
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +159 -155
- data/lib/active_record/inheritance.rb +93 -59
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +39 -43
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration/command_recorder.rb +102 -33
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +411 -173
- data/lib/active_record/model_schema.rb +81 -94
- data/lib/active_record/nested_attributes.rb +173 -131
- data/lib/active_record/null_relation.rb +67 -0
- data/lib/active_record/persistence.rb +254 -106
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +113 -38
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +4 -3
- data/lib/active_record/railties/databases.rake +115 -368
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +110 -61
- data/lib/active_record/relation/batches.rb +29 -29
- data/lib/active_record/relation/calculations.rb +155 -125
- data/lib/active_record/relation/delegation.rb +94 -18
- data/lib/active_record/relation/finder_methods.rb +151 -203
- data/lib/active_record/relation/merger.rb +188 -0
- data/lib/active_record/relation/predicate_builder.rb +85 -42
- data/lib/active_record/relation/query_methods.rb +793 -146
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/relation.rb +293 -173
- data/lib/active_record/result.rb +48 -7
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +41 -54
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +41 -41
- data/lib/active_record/schema_migration.rb +46 -0
- data/lib/active_record/scoping/default.rb +56 -52
- data/lib/active_record/scoping/named.rb +78 -103
- data/lib/active_record/scoping.rb +54 -124
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +131 -15
- data/lib/active_record/tasks/database_tasks.rb +204 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/test_case.rb +67 -38
- data/lib/active_record/timestamp.rb +16 -11
- data/lib/active_record/transactions.rb +73 -51
- data/lib/active_record/validations/associated.rb +19 -13
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +110 -57
- data/lib/active_record/validations.rb +18 -17
- data/lib/active_record/version.rb +7 -6
- data/lib/active_record.rb +63 -45
- data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -5
- metadata +43 -29
- data/examples/associations.png +0 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
class ConnectionSpecification #:nodoc:
|
6
|
+
attr_reader :config, :adapter_method
|
7
|
+
|
8
|
+
def initialize(config, adapter_method)
|
9
|
+
@config, @adapter_method = config, adapter_method
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_dup(original)
|
13
|
+
@config = original.config.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Builds a ConnectionSpecification from user input
|
18
|
+
class Resolver # :nodoc:
|
19
|
+
attr_reader :config, :klass, :configurations
|
20
|
+
|
21
|
+
def initialize(config, configurations)
|
22
|
+
@config = config
|
23
|
+
@configurations = configurations
|
24
|
+
end
|
25
|
+
|
26
|
+
def spec
|
27
|
+
case config
|
28
|
+
when nil
|
29
|
+
raise AdapterNotSpecified unless defined?(Rails.env)
|
30
|
+
resolve_string_connection Rails.env
|
31
|
+
when Symbol, String
|
32
|
+
resolve_string_connection config.to_s
|
33
|
+
when Hash
|
34
|
+
resolve_hash_connection config
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def resolve_string_connection(spec) # :nodoc:
|
40
|
+
hash = configurations.fetch(spec) do |k|
|
41
|
+
connection_url_to_hash(k)
|
42
|
+
end
|
43
|
+
|
44
|
+
raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash
|
45
|
+
|
46
|
+
resolve_hash_connection hash
|
47
|
+
end
|
48
|
+
|
49
|
+
def resolve_hash_connection(spec) # :nodoc:
|
50
|
+
spec = spec.symbolize_keys
|
51
|
+
|
52
|
+
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
53
|
+
|
54
|
+
path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
|
55
|
+
begin
|
56
|
+
require path_to_adapter
|
57
|
+
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."
|
59
|
+
rescue LoadError => e
|
60
|
+
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
|
+
end
|
62
|
+
|
63
|
+
adapter_method = "#{spec[:adapter]}_connection"
|
64
|
+
|
65
|
+
ConnectionSpecification.new(spec, adapter_method)
|
66
|
+
end
|
67
|
+
|
68
|
+
def connection_url_to_hash(url) # :nodoc:
|
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.hostname }
|
78
|
+
|
79
|
+
spec.reject!{ |_,value| value.blank? }
|
80
|
+
|
81
|
+
uri_parser = URI::Parser.new
|
82
|
+
|
83
|
+
spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) }
|
84
|
+
|
85
|
+
if config.query
|
86
|
+
options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys
|
87
|
+
|
88
|
+
spec.merge!(options)
|
89
|
+
end
|
90
|
+
|
91
|
+
spec
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -4,16 +4,18 @@ gem 'mysql2', '~> 0.3.10'
|
|
4
4
|
require 'mysql2'
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
|
-
|
7
|
+
module ConnectionHandling # :nodoc:
|
8
8
|
# Establishes a connection to the database that's used by all Active Record objects.
|
9
|
-
def
|
9
|
+
def mysql2_connection(config)
|
10
|
+
config = config.symbolize_keys
|
11
|
+
|
10
12
|
config[:username] = 'root' if config[:username].nil?
|
11
13
|
|
12
14
|
if Mysql2::Client.const_defined? :FOUND_ROWS
|
13
15
|
config[:flags] = Mysql2::Client::FOUND_ROWS
|
14
16
|
end
|
15
17
|
|
16
|
-
client = Mysql2::Client.new(config
|
18
|
+
client = Mysql2::Client.new(config)
|
17
19
|
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
18
20
|
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
19
21
|
end
|
@@ -36,6 +38,15 @@ module ActiveRecord
|
|
36
38
|
configure_connection
|
37
39
|
end
|
38
40
|
|
41
|
+
MAX_INDEX_LENGTH_FOR_UTF8MB4 = 191
|
42
|
+
def initialize_schema_migrations_table
|
43
|
+
if @config[:encoding] == 'utf8mb4'
|
44
|
+
ActiveRecord::SchemaMigration.create_table(MAX_INDEX_LENGTH_FOR_UTF8MB4)
|
45
|
+
else
|
46
|
+
ActiveRecord::SchemaMigration.create_table
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
39
50
|
def supports_explain?
|
40
51
|
true
|
41
52
|
end
|
@@ -52,8 +63,8 @@ module ActiveRecord
|
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
55
|
-
def new_column(field, default, type, null, collation) # :nodoc:
|
56
|
-
Column.new(field, default, type, null, collation)
|
66
|
+
def new_column(field, default, type, null, collation, extra = "") # :nodoc:
|
67
|
+
Column.new(field, default, type, null, collation, strict_mode?, extra)
|
57
68
|
end
|
58
69
|
|
59
70
|
def error_number(exception)
|
@@ -74,24 +85,22 @@ module ActiveRecord
|
|
74
85
|
end
|
75
86
|
|
76
87
|
def reconnect!
|
88
|
+
super
|
77
89
|
disconnect!
|
78
90
|
connect
|
79
91
|
end
|
92
|
+
alias :reset! :reconnect!
|
80
93
|
|
81
94
|
# Disconnects from the database if already connected.
|
82
95
|
# Otherwise, this method does nothing.
|
83
96
|
def disconnect!
|
97
|
+
super
|
84
98
|
unless @connection.nil?
|
85
99
|
@connection.close
|
86
100
|
@connection = nil
|
87
101
|
end
|
88
102
|
end
|
89
103
|
|
90
|
-
def reset!
|
91
|
-
disconnect!
|
92
|
-
connect
|
93
|
-
end
|
94
|
-
|
95
104
|
# DATABASE STATEMENTS ======================================
|
96
105
|
|
97
106
|
def explain(arel, binds = [])
|
@@ -177,7 +186,7 @@ module ActiveRecord
|
|
177
186
|
# # as values.
|
178
187
|
# def select_one(sql, name = nil)
|
179
188
|
# result = execute(sql, name)
|
180
|
-
# result.each(:
|
189
|
+
# result.each(as: :hash) do |r|
|
181
190
|
# return r
|
182
191
|
# end
|
183
192
|
# end
|
@@ -198,7 +207,7 @@ module ActiveRecord
|
|
198
207
|
|
199
208
|
# Returns an array of arrays containing the field values.
|
200
209
|
# Order is the same as that returned by +columns+.
|
201
|
-
def select_rows(sql, name = nil)
|
210
|
+
def select_rows(sql, name = nil, binds = [])
|
202
211
|
execute(sql, name).to_a
|
203
212
|
end
|
204
213
|
|
@@ -223,7 +232,7 @@ module ActiveRecord
|
|
223
232
|
# Returns an array of record hashes with the column names as keys and
|
224
233
|
# column values as values.
|
225
234
|
def select(sql, name = nil, binds = [])
|
226
|
-
exec_query(sql, name)
|
235
|
+
exec_query(sql, name)
|
227
236
|
end
|
228
237
|
|
229
238
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
@@ -232,7 +241,7 @@ module ActiveRecord
|
|
232
241
|
end
|
233
242
|
alias :create :insert_sql
|
234
243
|
|
235
|
-
def exec_insert(sql, name, binds)
|
244
|
+
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
236
245
|
execute to_sql(sql, binds), name
|
237
246
|
end
|
238
247
|
|
@@ -255,26 +264,16 @@ module ActiveRecord
|
|
255
264
|
|
256
265
|
def configure_connection
|
257
266
|
@connection.query_options.merge!(:as => :array)
|
258
|
-
|
259
|
-
# By default, MySQL 'where id is null' selects the last inserted id.
|
260
|
-
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
261
|
-
variable_assignments = ['SQL_AUTO_IS_NULL=0']
|
262
|
-
encoding = @config[:encoding]
|
263
|
-
|
264
|
-
# make sure we set the encoding
|
265
|
-
variable_assignments << "NAMES '#{encoding}'" if encoding
|
266
|
-
|
267
|
-
# increase timeout so mysql server doesn't disconnect us
|
268
|
-
wait_timeout = @config[:wait_timeout]
|
269
|
-
wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
|
270
|
-
variable_assignments << "@@wait_timeout = #{wait_timeout}"
|
271
|
-
|
272
|
-
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
|
267
|
+
super
|
273
268
|
end
|
274
269
|
|
275
270
|
def version
|
276
271
|
@version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
277
272
|
end
|
273
|
+
|
274
|
+
def set_field_encoding field_name
|
275
|
+
field_name
|
276
|
+
end
|
278
277
|
end
|
279
278
|
end
|
280
279
|
end
|
@@ -2,13 +2,11 @@ require 'active_record/connection_adapters/abstract_mysql_adapter'
|
|
2
2
|
require 'active_record/connection_adapters/statement_pool'
|
3
3
|
require 'active_support/core_ext/hash/keys'
|
4
4
|
|
5
|
-
gem 'mysql', '~> 2.
|
5
|
+
gem 'mysql', '~> 2.9'
|
6
6
|
require 'mysql'
|
7
7
|
|
8
8
|
class Mysql
|
9
9
|
class Time
|
10
|
-
###
|
11
|
-
# This monkey patch is for test_additional_columns_from_join_table
|
12
10
|
def to_date
|
13
11
|
Date.new(year, month, day)
|
14
12
|
end
|
@@ -18,9 +16,9 @@ class Mysql
|
|
18
16
|
end
|
19
17
|
|
20
18
|
module ActiveRecord
|
21
|
-
|
19
|
+
module ConnectionHandling # :nodoc:
|
22
20
|
# Establishes a connection to the database that's used by all Active Record objects.
|
23
|
-
def
|
21
|
+
def mysql_connection(config)
|
24
22
|
config = config.symbolize_keys
|
25
23
|
host = config[:host]
|
26
24
|
port = config[:port]
|
@@ -53,6 +51,8 @@ module ActiveRecord
|
|
53
51
|
# * <tt>:database</tt> - The name of the database. No default, must be provided.
|
54
52
|
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
|
55
53
|
# * <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/server-sql-mode.html)
|
55
|
+
# * <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
56
|
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
|
57
57
|
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
|
58
58
|
# * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
|
@@ -119,14 +119,14 @@ module ActiveRecord
|
|
119
119
|
|
120
120
|
private
|
121
121
|
def cache
|
122
|
-
@cache[
|
122
|
+
@cache[Process.pid]
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
126
|
def initialize(connection, logger, connection_options, config)
|
127
127
|
super
|
128
128
|
@statements = StatementPool.new(@connection,
|
129
|
-
config.fetch(:statement_limit) { 1000 })
|
129
|
+
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
130
130
|
@client_encoding = nil
|
131
131
|
connect
|
132
132
|
end
|
@@ -150,8 +150,8 @@ module ActiveRecord
|
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
|
-
def new_column(field, default, type, null, collation) # :nodoc:
|
154
|
-
Column.new(field, default, type, null, collation)
|
153
|
+
def new_column(field, default, type, null, collation, extra = "") # :nodoc:
|
154
|
+
Column.new(field, default, type, null, collation, strict_mode?, extra)
|
155
155
|
end
|
156
156
|
|
157
157
|
def error_number(exception) # :nodoc:
|
@@ -190,14 +190,15 @@ module ActiveRecord
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def reconnect!
|
193
|
+
super
|
193
194
|
disconnect!
|
194
|
-
clear_cache!
|
195
195
|
connect
|
196
196
|
end
|
197
197
|
|
198
198
|
# Disconnects from the database if already connected. Otherwise, this
|
199
199
|
# method does nothing.
|
200
200
|
def disconnect!
|
201
|
+
super
|
201
202
|
@connection.close rescue nil
|
202
203
|
end
|
203
204
|
|
@@ -212,9 +213,9 @@ module ActiveRecord
|
|
212
213
|
|
213
214
|
# DATABASE STATEMENTS ======================================
|
214
215
|
|
215
|
-
def select_rows(sql, name = nil)
|
216
|
+
def select_rows(sql, name = nil, binds = [])
|
216
217
|
@connection.query_with_result = true
|
217
|
-
rows = exec_query(sql, name).rows
|
218
|
+
rows = exec_query(sql, name, binds).rows
|
218
219
|
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
219
220
|
rows
|
220
221
|
end
|
@@ -224,52 +225,48 @@ module ActiveRecord
|
|
224
225
|
@statements.clear
|
225
226
|
end
|
226
227
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
}
|
270
|
-
else
|
271
|
-
ENCODINGS = Hash.new { |h,k| h[k] = k }
|
272
|
-
end
|
228
|
+
# Taken from here:
|
229
|
+
# https://github.com/tmtm/ruby-mysql/blob/master/lib/mysql/charset.rb
|
230
|
+
# Author: TOMITA Masahiro <tommy@tmtm.org>
|
231
|
+
ENCODINGS = {
|
232
|
+
"armscii8" => nil,
|
233
|
+
"ascii" => Encoding::US_ASCII,
|
234
|
+
"big5" => Encoding::Big5,
|
235
|
+
"binary" => Encoding::ASCII_8BIT,
|
236
|
+
"cp1250" => Encoding::Windows_1250,
|
237
|
+
"cp1251" => Encoding::Windows_1251,
|
238
|
+
"cp1256" => Encoding::Windows_1256,
|
239
|
+
"cp1257" => Encoding::Windows_1257,
|
240
|
+
"cp850" => Encoding::CP850,
|
241
|
+
"cp852" => Encoding::CP852,
|
242
|
+
"cp866" => Encoding::IBM866,
|
243
|
+
"cp932" => Encoding::Windows_31J,
|
244
|
+
"dec8" => nil,
|
245
|
+
"eucjpms" => Encoding::EucJP_ms,
|
246
|
+
"euckr" => Encoding::EUC_KR,
|
247
|
+
"gb2312" => Encoding::EUC_CN,
|
248
|
+
"gbk" => Encoding::GBK,
|
249
|
+
"geostd8" => nil,
|
250
|
+
"greek" => Encoding::ISO_8859_7,
|
251
|
+
"hebrew" => Encoding::ISO_8859_8,
|
252
|
+
"hp8" => nil,
|
253
|
+
"keybcs2" => nil,
|
254
|
+
"koi8r" => Encoding::KOI8_R,
|
255
|
+
"koi8u" => Encoding::KOI8_U,
|
256
|
+
"latin1" => Encoding::ISO_8859_1,
|
257
|
+
"latin2" => Encoding::ISO_8859_2,
|
258
|
+
"latin5" => Encoding::ISO_8859_9,
|
259
|
+
"latin7" => Encoding::ISO_8859_13,
|
260
|
+
"macce" => Encoding::MacCentEuro,
|
261
|
+
"macroman" => Encoding::MacRoman,
|
262
|
+
"sjis" => Encoding::SHIFT_JIS,
|
263
|
+
"swe7" => nil,
|
264
|
+
"tis620" => Encoding::TIS_620,
|
265
|
+
"ucs2" => Encoding::UTF_16BE,
|
266
|
+
"ujis" => Encoding::EucJP_ms,
|
267
|
+
"utf8" => Encoding::UTF_8,
|
268
|
+
"utf8mb4" => Encoding::UTF_8,
|
269
|
+
}
|
273
270
|
|
274
271
|
# Get the client encoding for this database
|
275
272
|
def client_encoding
|
@@ -282,11 +279,7 @@ module ActiveRecord
|
|
282
279
|
end
|
283
280
|
|
284
281
|
def exec_query(sql, name = 'SQL', binds = [])
|
285
|
-
|
286
|
-
# always be empty, since the bind variables will have been already
|
287
|
-
# substituted and removed from binds by BindVisitor, so this will
|
288
|
-
# effectively disable prepared statement usage completely.
|
289
|
-
if binds.empty?
|
282
|
+
if without_prepared_statement?(binds)
|
290
283
|
result_set, affected_rows = exec_without_stmt(sql, name)
|
291
284
|
else
|
292
285
|
result_set, affected_rows = exec_stmt(sql, name, binds)
|
@@ -301,6 +294,128 @@ module ActiveRecord
|
|
301
294
|
@connection.insert_id
|
302
295
|
end
|
303
296
|
|
297
|
+
module Fields
|
298
|
+
class Type
|
299
|
+
def type; end
|
300
|
+
|
301
|
+
def type_cast_for_write(value)
|
302
|
+
value
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
class Identity < Type
|
307
|
+
def type_cast(value); value; end
|
308
|
+
end
|
309
|
+
|
310
|
+
class Integer < Type
|
311
|
+
def type_cast(value)
|
312
|
+
return if value.nil?
|
313
|
+
|
314
|
+
value.to_i rescue value ? 1 : 0
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
class Date < Type
|
319
|
+
def type; :date; end
|
320
|
+
|
321
|
+
def type_cast(value)
|
322
|
+
return if value.nil?
|
323
|
+
|
324
|
+
# FIXME: probably we can improve this since we know it is mysql
|
325
|
+
# specific
|
326
|
+
ConnectionAdapters::Column.value_to_date value
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
class DateTime < Type
|
331
|
+
def type; :datetime; end
|
332
|
+
|
333
|
+
def type_cast(value)
|
334
|
+
return if value.nil?
|
335
|
+
|
336
|
+
# FIXME: probably we can improve this since we know it is mysql
|
337
|
+
# specific
|
338
|
+
ConnectionAdapters::Column.string_to_time value
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
class Time < Type
|
343
|
+
def type; :time; end
|
344
|
+
|
345
|
+
def type_cast(value)
|
346
|
+
return if value.nil?
|
347
|
+
|
348
|
+
# FIXME: probably we can improve this since we know it is mysql
|
349
|
+
# specific
|
350
|
+
ConnectionAdapters::Column.string_to_dummy_time value
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
class Float < Type
|
355
|
+
def type; :float; end
|
356
|
+
|
357
|
+
def type_cast(value)
|
358
|
+
return if value.nil?
|
359
|
+
|
360
|
+
value.to_f
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
class Decimal < Type
|
365
|
+
def type_cast(value)
|
366
|
+
return if value.nil?
|
367
|
+
|
368
|
+
ConnectionAdapters::Column.value_to_decimal value
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class Boolean < Type
|
373
|
+
def type_cast(value)
|
374
|
+
return if value.nil?
|
375
|
+
|
376
|
+
ConnectionAdapters::Column.value_to_boolean value
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
TYPES = {}
|
381
|
+
|
382
|
+
# Register an MySQL +type_id+ with a typecasting object in
|
383
|
+
# +type+.
|
384
|
+
def self.register_type(type_id, type)
|
385
|
+
TYPES[type_id] = type
|
386
|
+
end
|
387
|
+
|
388
|
+
def self.alias_type(new, old)
|
389
|
+
TYPES[new] = TYPES[old]
|
390
|
+
end
|
391
|
+
|
392
|
+
def self.find_type(field)
|
393
|
+
if field.type == Mysql::Field::TYPE_TINY && field.length > 1
|
394
|
+
TYPES[Mysql::Field::TYPE_LONG]
|
395
|
+
else
|
396
|
+
TYPES.fetch(field.type) { Fields::Identity.new }
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
register_type Mysql::Field::TYPE_TINY, Fields::Boolean.new
|
401
|
+
register_type Mysql::Field::TYPE_LONG, Fields::Integer.new
|
402
|
+
alias_type Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_LONG
|
403
|
+
alias_type Mysql::Field::TYPE_NEWDECIMAL, Mysql::Field::TYPE_LONG
|
404
|
+
|
405
|
+
register_type Mysql::Field::TYPE_VAR_STRING, Fields::Identity.new
|
406
|
+
register_type Mysql::Field::TYPE_BLOB, Fields::Identity.new
|
407
|
+
register_type Mysql::Field::TYPE_DATE, Fields::Date.new
|
408
|
+
register_type Mysql::Field::TYPE_DATETIME, Fields::DateTime.new
|
409
|
+
register_type Mysql::Field::TYPE_TIME, Fields::Time.new
|
410
|
+
register_type Mysql::Field::TYPE_FLOAT, Fields::Float.new
|
411
|
+
|
412
|
+
Mysql::Field.constants.grep(/TYPE/).map { |class_name|
|
413
|
+
Mysql::Field.const_get class_name
|
414
|
+
}.reject { |const| TYPES.key? const }.each do |const|
|
415
|
+
register_type const, Fields::Identity.new
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
304
419
|
def exec_without_stmt(sql, name = 'SQL') # :nodoc:
|
305
420
|
# Some queries, like SHOW CREATE TABLE don't work through the prepared
|
306
421
|
# statement API. For those queries, we need to use this method. :'(
|
@@ -309,8 +424,15 @@ module ActiveRecord
|
|
309
424
|
affected_rows = @connection.affected_rows
|
310
425
|
|
311
426
|
if result
|
312
|
-
|
313
|
-
|
427
|
+
types = {}
|
428
|
+
result.fetch_fields.each { |field|
|
429
|
+
if field.decimals > 0
|
430
|
+
types[field.name] = Fields::Decimal.new
|
431
|
+
else
|
432
|
+
types[field.name] = Fields.find_type field
|
433
|
+
end
|
434
|
+
}
|
435
|
+
result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
|
314
436
|
result.free
|
315
437
|
else
|
316
438
|
result_set = ActiveRecord::Result.new([], [])
|
@@ -381,12 +503,12 @@ module ActiveRecord
|
|
381
503
|
cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
|
382
504
|
field.name
|
383
505
|
}
|
506
|
+
metadata.free
|
384
507
|
end
|
385
508
|
|
386
509
|
result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
|
387
510
|
affected_rows = stmt.affected_rows
|
388
511
|
|
389
|
-
stmt.result_metadata.free if cols
|
390
512
|
stmt.free_result
|
391
513
|
stmt.close if binds.empty?
|
392
514
|
|
@@ -416,18 +538,15 @@ module ActiveRecord
|
|
416
538
|
configure_connection
|
417
539
|
end
|
418
540
|
|
541
|
+
# Many Rails applications monkey-patch a replacement of the configure_connection method
|
542
|
+
# and don't call 'super', so leave this here even though it looks superfluous.
|
419
543
|
def configure_connection
|
420
|
-
|
421
|
-
execute("SET NAMES '#{encoding}'", :skip_logging) if encoding
|
422
|
-
|
423
|
-
# By default, MySQL 'where id is null' selects the last inserted id.
|
424
|
-
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
425
|
-
execute("SET SQL_AUTO_IS_NULL=0", :skip_logging)
|
544
|
+
super
|
426
545
|
end
|
427
546
|
|
428
547
|
def select(sql, name = nil, binds = [])
|
429
548
|
@connection.query_with_result = true
|
430
|
-
rows = exec_query(sql, name, binds)
|
549
|
+
rows = exec_query(sql, name, binds)
|
431
550
|
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
432
551
|
rows
|
433
552
|
end
|
@@ -436,6 +555,14 @@ module ActiveRecord
|
|
436
555
|
def version
|
437
556
|
@version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
438
557
|
end
|
558
|
+
|
559
|
+
def set_field_encoding field_name
|
560
|
+
field_name.force_encoding(client_encoding)
|
561
|
+
if internal_enc = Encoding.default_internal
|
562
|
+
field_name = field_name.encode!(internal_enc)
|
563
|
+
end
|
564
|
+
field_name
|
565
|
+
end
|
439
566
|
end
|
440
567
|
end
|
441
568
|
end
|