activerecord 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2102 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +35 -44
- data/examples/performance.rb +110 -100
- data/lib/active_record/aggregations.rb +59 -75
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +248 -0
- data/lib/active_record/associations/association_scope.rb +135 -0
- data/lib/active_record/associations/belongs_to_association.rb +60 -59
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
- data/lib/active_record/associations/builder/association.rb +108 -0
- data/lib/active_record/associations/builder/belongs_to.rb +98 -0
- data/lib/active_record/associations/builder/collection_association.rb +89 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +25 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +608 -0
- data/lib/active_record/associations/collection_proxy.rb +986 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
- data/lib/active_record/associations/has_many_association.rb +83 -76
- data/lib/active_record/associations/has_many_through_association.rb +147 -66
- data/lib/active_record/associations/has_one_association.rb +67 -108
- data/lib/active_record/associations/has_one_through_association.rb +21 -25
- data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +235 -0
- data/lib/active_record/associations/join_helper.rb +45 -0
- data/lib/active_record/associations/preloader/association.rb +121 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +63 -0
- data/lib/active_record/associations/preloader.rb +178 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +512 -1224
- data/lib/active_record/attribute_assignment.rb +201 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
- data/lib/active_record/attribute_methods/dirty.rb +51 -28
- data/lib/active_record/attribute_methods/primary_key.rb +94 -22
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +63 -72
- data/lib/active_record/attribute_methods/serialization.rb +162 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
- data/lib/active_record/attribute_methods/write.rb +39 -13
- data/lib/active_record/attribute_methods.rb +362 -29
- data/lib/active_record/autosave_association.rb +132 -75
- data/lib/active_record/base.rb +83 -1627
- data/lib/active_record/callbacks.rb +69 -47
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
- data/lib/active_record/connection_adapters/column.rb +318 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
- data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +463 -0
- data/lib/active_record/counter_cache.rb +108 -101
- data/lib/active_record/dynamic_matchers.rb +131 -0
- data/lib/active_record/errors.rb +54 -13
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +703 -785
- data/lib/active_record/inheritance.rb +200 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +69 -60
- data/lib/active_record/locking/pessimistic.rb +34 -12
- data/lib/active_record/log_subscriber.rb +40 -6
- data/lib/active_record/migration/command_recorder.rb +164 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +614 -216
- data/lib/active_record/model_schema.rb +345 -0
- data/lib/active_record/nested_attributes.rb +248 -119
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +275 -57
- data/lib/active_record/query_cache.rb +29 -9
- data/lib/active_record/querying.rb +62 -0
- data/lib/active_record/railtie.rb +135 -21
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +17 -5
- data/lib/active_record/railties/databases.rake +249 -359
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +30 -0
- data/lib/active_record/reflection.rb +283 -103
- data/lib/active_record/relation/batches.rb +38 -34
- data/lib/active_record/relation/calculations.rb +252 -139
- data/lib/active_record/relation/delegation.rb +125 -0
- data/lib/active_record/relation/finder_methods.rb +182 -188
- data/lib/active_record/relation/merger.rb +161 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -21
- data/lib/active_record/relation/query_methods.rb +917 -134
- data/lib/active_record/relation/spawn_methods.rb +53 -92
- data/lib/active_record/relation.rb +405 -143
- data/lib/active_record/result.rb +67 -0
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +168 -0
- data/lib/active_record/schema.rb +20 -14
- data/lib/active_record/schema_dumper.rb +55 -46
- data/lib/active_record/schema_migration.rb +39 -0
- data/lib/active_record/scoping/default.rb +146 -0
- data/lib/active_record/scoping/named.rb +175 -0
- data/lib/active_record/scoping.rb +82 -0
- data/lib/active_record/serialization.rb +8 -46
- data/lib/active_record/serializers/xml_serializer.rb +21 -68
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +156 -0
- data/lib/active_record/tasks/database_tasks.rb +203 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +143 -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 +57 -28
- data/lib/active_record/timestamp.rb +49 -18
- data/lib/active_record/transactions.rb +106 -63
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +25 -24
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +123 -83
- data/lib/active_record/validations.rb +29 -29
- data/lib/active_record/version.rb +7 -5
- data/lib/active_record.rb +83 -34
- data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
- data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
- data/lib/rails/generators/active_record.rb +4 -8
- metadata +163 -121
- data/CHANGELOG +0 -6023
- data/examples/associations.png +0 -0
- data/lib/active_record/association_preload.rb +0 -403
- data/lib/active_record/associations/association_collection.rb +0 -562
- data/lib/active_record/associations/association_proxy.rb +0 -295
- data/lib/active_record/associations/through_association_scope.rb +0 -154
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
- data/lib/active_record/dynamic_finder_match.rb +0 -53
- data/lib/active_record/dynamic_scope_match.rb +0 -32
- data/lib/active_record/named_scope.rb +0 -138
- data/lib/active_record/observer.rb +0 -140
- data/lib/active_record/session_store.rb +0 -340
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,12 +1,24 @@
|
|
1
|
-
require 'active_record/connection_adapters/
|
2
|
-
require '
|
3
|
-
require 'active_support/core_ext/
|
4
|
-
|
1
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
2
|
+
require 'active_record/connection_adapters/statement_pool'
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
4
|
+
|
5
|
+
gem 'mysql', '~> 2.9'
|
6
|
+
require 'mysql'
|
7
|
+
|
8
|
+
class Mysql
|
9
|
+
class Time
|
10
|
+
def to_date
|
11
|
+
Date.new(year, month, day)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
class Stmt; include Enumerable end
|
15
|
+
class Result; include Enumerable end
|
16
|
+
end
|
5
17
|
|
6
18
|
module ActiveRecord
|
7
|
-
|
19
|
+
module ConnectionHandling # :nodoc:
|
8
20
|
# Establishes a connection to the database that's used by all Active Record objects.
|
9
|
-
def
|
21
|
+
def mysql_connection(config)
|
10
22
|
config = config.symbolize_keys
|
11
23
|
host = config[:host]
|
12
24
|
port = config[:port]
|
@@ -15,18 +27,6 @@ module ActiveRecord
|
|
15
27
|
password = config[:password].to_s
|
16
28
|
database = config[:database]
|
17
29
|
|
18
|
-
unless defined? Mysql
|
19
|
-
begin
|
20
|
-
require 'mysql'
|
21
|
-
rescue LoadError
|
22
|
-
raise "!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql', '2.8.1'"
|
23
|
-
end
|
24
|
-
|
25
|
-
unless defined?(Mysql::Result) && Mysql::Result.method_defined?(:each_hash)
|
26
|
-
raise "!!! Outdated mysql gem. Upgrade to 2.8.1 or later. In your Gemfile: gem 'mysql', '2.8.1'"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
30
|
mysql = Mysql.init
|
31
31
|
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey]
|
32
32
|
|
@@ -38,68 +38,6 @@ module ActiveRecord
|
|
38
38
|
end
|
39
39
|
|
40
40
|
module ConnectionAdapters
|
41
|
-
class MysqlColumn < Column #:nodoc:
|
42
|
-
def extract_default(default)
|
43
|
-
if sql_type =~ /blob/i || type == :text
|
44
|
-
if default.blank?
|
45
|
-
return null ? nil : ''
|
46
|
-
else
|
47
|
-
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
48
|
-
end
|
49
|
-
elsif missing_default_forged_as_empty_string?(default)
|
50
|
-
nil
|
51
|
-
else
|
52
|
-
super
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def has_default?
|
57
|
-
return false if sql_type =~ /blob/i || type == :text #mysql forbids defaults on blob and text columns
|
58
|
-
super
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
def simplified_type(field_type)
|
63
|
-
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
|
64
|
-
return :string if field_type =~ /enum/i
|
65
|
-
super
|
66
|
-
end
|
67
|
-
|
68
|
-
def extract_limit(sql_type)
|
69
|
-
case sql_type
|
70
|
-
when /blob|text/i
|
71
|
-
case sql_type
|
72
|
-
when /tiny/i
|
73
|
-
255
|
74
|
-
when /medium/i
|
75
|
-
16777215
|
76
|
-
when /long/i
|
77
|
-
2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases
|
78
|
-
else
|
79
|
-
super # we could return 65535 here, but we leave it undecorated by default
|
80
|
-
end
|
81
|
-
when /^bigint/i; 8
|
82
|
-
when /^int/i; 4
|
83
|
-
when /^mediumint/i; 3
|
84
|
-
when /^smallint/i; 2
|
85
|
-
when /^tinyint/i; 1
|
86
|
-
else
|
87
|
-
super
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# MySQL misreports NOT NULL column default when none is given.
|
92
|
-
# We can't detect this for columns which may have a legitimate ''
|
93
|
-
# default (string) but we can for others (integer, datetime, boolean,
|
94
|
-
# and the rest).
|
95
|
-
#
|
96
|
-
# Test whether the column has default '', is not null, and is not
|
97
|
-
# a type allowing default ''.
|
98
|
-
def missing_default_forged_as_empty_string?(default)
|
99
|
-
type != :string && !null && default == ''
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
41
|
# The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with
|
104
42
|
# the faster C-based MySQL/Ruby adapter (available both as a gem and from http://www.tmtm.org/en/mysql/ruby/).
|
105
43
|
#
|
@@ -113,122 +51,123 @@ module ActiveRecord
|
|
113
51
|
# * <tt>:database</tt> - The name of the database. No default, must be provided.
|
114
52
|
# * <tt>:encoding</tt> - (Optional) Sets the client encoding by executing "SET NAMES <encoding>" after connection.
|
115
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).
|
116
56
|
# * <tt>:sslca</tt> - Necessary to use MySQL with an SSL connection.
|
117
57
|
# * <tt>:sslkey</tt> - Necessary to use MySQL with an SSL connection.
|
118
58
|
# * <tt>:sslcert</tt> - Necessary to use MySQL with an SSL connection.
|
119
59
|
# * <tt>:sslcapath</tt> - Necessary to use MySQL with an SSL connection.
|
120
60
|
# * <tt>:sslcipher</tt> - Necessary to use MySQL with an SSL connection.
|
121
61
|
#
|
122
|
-
class MysqlAdapter <
|
123
|
-
|
124
|
-
##
|
125
|
-
# :singleton-method:
|
126
|
-
# By default, the MysqlAdapter will consider all columns of type <tt>tinyint(1)</tt>
|
127
|
-
# as boolean. If you wish to disable this emulation (which was the default
|
128
|
-
# behavior in versions 0.13.1 and earlier) you can add the following line
|
129
|
-
# to your application.rb file:
|
130
|
-
#
|
131
|
-
# ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false
|
132
|
-
cattr_accessor :emulate_booleans
|
133
|
-
self.emulate_booleans = true
|
134
|
-
|
135
|
-
ADAPTER_NAME = 'MySQL'.freeze
|
136
|
-
|
137
|
-
LOST_CONNECTION_ERROR_MESSAGES = [
|
138
|
-
"Server shutdown in progress",
|
139
|
-
"Broken pipe",
|
140
|
-
"Lost connection to MySQL server during query",
|
141
|
-
"MySQL server has gone away" ]
|
142
|
-
|
143
|
-
QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
|
144
|
-
|
145
|
-
NATIVE_DATABASE_TYPES = {
|
146
|
-
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
|
147
|
-
:string => { :name => "varchar", :limit => 255 },
|
148
|
-
:text => { :name => "text" },
|
149
|
-
:integer => { :name => "int", :limit => 4 },
|
150
|
-
:float => { :name => "float" },
|
151
|
-
:decimal => { :name => "decimal" },
|
152
|
-
:datetime => { :name => "datetime" },
|
153
|
-
:timestamp => { :name => "datetime" },
|
154
|
-
:time => { :name => "time" },
|
155
|
-
:date => { :name => "date" },
|
156
|
-
:binary => { :name => "blob" },
|
157
|
-
:boolean => { :name => "tinyint", :limit => 1 }
|
158
|
-
}
|
62
|
+
class MysqlAdapter < AbstractMysqlAdapter
|
159
63
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
64
|
+
class Column < AbstractMysqlAdapter::Column #:nodoc:
|
65
|
+
def self.string_to_time(value)
|
66
|
+
return super unless Mysql::Time === value
|
67
|
+
new_time(
|
68
|
+
value.year,
|
69
|
+
value.month,
|
70
|
+
value.day,
|
71
|
+
value.hour,
|
72
|
+
value.minute,
|
73
|
+
value.second,
|
74
|
+
value.second_part)
|
75
|
+
end
|
166
76
|
|
167
|
-
|
168
|
-
|
169
|
-
|
77
|
+
def self.string_to_dummy_time(v)
|
78
|
+
return super unless Mysql::Time === v
|
79
|
+
new_time(2000, 01, 01, v.hour, v.minute, v.second, v.second_part)
|
80
|
+
end
|
170
81
|
|
171
|
-
|
172
|
-
|
173
|
-
|
82
|
+
def self.string_to_date(v)
|
83
|
+
return super unless Mysql::Time === v
|
84
|
+
new_date(v.year, v.month, v.day)
|
85
|
+
end
|
174
86
|
|
175
|
-
|
176
|
-
|
87
|
+
def adapter
|
88
|
+
MysqlAdapter
|
89
|
+
end
|
177
90
|
end
|
178
91
|
|
179
|
-
|
180
|
-
true
|
181
|
-
end
|
92
|
+
ADAPTER_NAME = 'MySQL'
|
182
93
|
|
183
|
-
|
184
|
-
|
185
|
-
|
94
|
+
class StatementPool < ConnectionAdapters::StatementPool
|
95
|
+
def initialize(connection, max = 1000)
|
96
|
+
super
|
97
|
+
@cache = Hash.new { |h,pid| h[pid] = {} }
|
98
|
+
end
|
186
99
|
|
100
|
+
def each(&block); cache.each(&block); end
|
101
|
+
def key?(key); cache.key?(key); end
|
102
|
+
def [](key); cache[key]; end
|
103
|
+
def length; cache.length; end
|
104
|
+
def delete(key); cache.delete(key); end
|
187
105
|
|
188
|
-
|
106
|
+
def []=(sql, key)
|
107
|
+
while @max <= cache.size
|
108
|
+
cache.shift.last[:stmt].close
|
109
|
+
end
|
110
|
+
cache[sql] = key
|
111
|
+
end
|
189
112
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
113
|
+
def clear
|
114
|
+
cache.values.each do |hash|
|
115
|
+
hash[:stmt].close
|
116
|
+
end
|
117
|
+
cache.clear
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def cache
|
122
|
+
@cache[Process.pid]
|
198
123
|
end
|
199
124
|
end
|
200
125
|
|
201
|
-
def
|
202
|
-
|
126
|
+
def initialize(connection, logger, connection_options, config)
|
127
|
+
super
|
128
|
+
@statements = StatementPool.new(@connection,
|
129
|
+
self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
|
130
|
+
@client_encoding = nil
|
131
|
+
connect
|
203
132
|
end
|
204
133
|
|
205
|
-
|
206
|
-
|
134
|
+
# Returns true, since this connection adapter supports prepared statement
|
135
|
+
# caching.
|
136
|
+
def supports_statement_cache?
|
137
|
+
true
|
207
138
|
end
|
208
139
|
|
209
|
-
|
210
|
-
|
140
|
+
# HELPER METHODS ===========================================
|
141
|
+
|
142
|
+
def each_hash(result) # :nodoc:
|
143
|
+
if block_given?
|
144
|
+
result.each_hash do |row|
|
145
|
+
row.symbolize_keys!
|
146
|
+
yield row
|
147
|
+
end
|
148
|
+
else
|
149
|
+
to_enum(:each_hash, result)
|
150
|
+
end
|
211
151
|
end
|
212
152
|
|
213
|
-
def
|
214
|
-
|
153
|
+
def new_column(field, default, type, null, collation, extra = "") # :nodoc:
|
154
|
+
Column.new(field, default, type, null, collation, strict_mode?, extra)
|
215
155
|
end
|
216
156
|
|
217
|
-
def
|
218
|
-
|
157
|
+
def error_number(exception) # :nodoc:
|
158
|
+
exception.errno if exception.respond_to?(:errno)
|
219
159
|
end
|
220
160
|
|
221
|
-
#
|
161
|
+
# QUOTING ==================================================
|
222
162
|
|
223
|
-
def
|
224
|
-
|
163
|
+
def type_cast(value, column)
|
164
|
+
return super unless value == true || value == false
|
225
165
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
end
|
166
|
+
value ? 1 : 0
|
167
|
+
end
|
168
|
+
|
169
|
+
def quote_string(string) #:nodoc:
|
170
|
+
@connection.quote(string)
|
232
171
|
end
|
233
172
|
|
234
173
|
# CONNECTION MANAGEMENT ====================================
|
@@ -251,11 +190,15 @@ module ActiveRecord
|
|
251
190
|
end
|
252
191
|
|
253
192
|
def reconnect!
|
193
|
+
super
|
254
194
|
disconnect!
|
255
195
|
connect
|
256
196
|
end
|
257
197
|
|
198
|
+
# Disconnects from the database if already connected. Otherwise, this
|
199
|
+
# method does nothing.
|
258
200
|
def disconnect!
|
201
|
+
super
|
259
202
|
@connection.close rescue nil
|
260
203
|
end
|
261
204
|
|
@@ -272,372 +215,344 @@ module ActiveRecord
|
|
272
215
|
|
273
216
|
def select_rows(sql, name = nil)
|
274
217
|
@connection.query_with_result = true
|
275
|
-
|
276
|
-
|
277
|
-
result.each { |row| rows << row }
|
278
|
-
result.free
|
279
|
-
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
218
|
+
rows = exec_query(sql, name).rows
|
219
|
+
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
280
220
|
rows
|
281
221
|
end
|
282
222
|
|
283
|
-
#
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
223
|
+
# Clears the prepared statements cache.
|
224
|
+
def clear_cache!
|
225
|
+
@statements.clear
|
226
|
+
end
|
227
|
+
|
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
|
+
}
|
298
270
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
end
|
303
|
-
alias :create :insert_sql
|
271
|
+
# Get the client encoding for this database
|
272
|
+
def client_encoding
|
273
|
+
return @client_encoding if @client_encoding
|
304
274
|
|
305
|
-
|
306
|
-
|
307
|
-
|
275
|
+
result = exec_query(
|
276
|
+
"SHOW VARIABLES WHERE Variable_name = 'character_set_client'",
|
277
|
+
'SCHEMA')
|
278
|
+
@client_encoding = ENCODINGS[result.rows.last.last]
|
308
279
|
end
|
309
280
|
|
310
|
-
def
|
311
|
-
|
312
|
-
|
313
|
-
#
|
314
|
-
|
281
|
+
def exec_query(sql, name = 'SQL', binds = [])
|
282
|
+
# If the configuration sets prepared_statements:false, binds will
|
283
|
+
# always be empty, since the bind variables will have been already
|
284
|
+
# substituted and removed from binds by BindVisitor, so this will
|
285
|
+
# effectively disable prepared statement usage completely.
|
286
|
+
if binds.empty?
|
287
|
+
result_set, affected_rows = exec_without_stmt(sql, name)
|
288
|
+
else
|
289
|
+
result_set, affected_rows = exec_stmt(sql, name, binds)
|
290
|
+
end
|
315
291
|
|
316
|
-
|
317
|
-
execute "COMMIT"
|
318
|
-
rescue Exception
|
319
|
-
# Transactions aren't supported
|
320
|
-
end
|
292
|
+
yield affected_rows if block_given?
|
321
293
|
|
322
|
-
|
323
|
-
execute "ROLLBACK"
|
324
|
-
rescue Exception
|
325
|
-
# Transactions aren't supported
|
294
|
+
result_set
|
326
295
|
end
|
327
296
|
|
328
|
-
def
|
329
|
-
|
297
|
+
def last_inserted_id(result)
|
298
|
+
@connection.insert_id
|
330
299
|
end
|
331
300
|
|
332
|
-
|
333
|
-
|
334
|
-
|
301
|
+
module Fields
|
302
|
+
class Type
|
303
|
+
def type; end
|
335
304
|
|
336
|
-
|
337
|
-
|
338
|
-
|
305
|
+
def type_cast_for_write(value)
|
306
|
+
value
|
307
|
+
end
|
308
|
+
end
|
339
309
|
|
340
|
-
|
341
|
-
|
342
|
-
if limit && offset
|
343
|
-
sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
|
344
|
-
elsif limit
|
345
|
-
sql << " LIMIT #{sanitize_limit(limit)}"
|
346
|
-
elsif offset
|
347
|
-
sql << " OFFSET #{offset.to_i}"
|
310
|
+
class Identity < Type
|
311
|
+
def type_cast(value); value; end
|
348
312
|
end
|
349
|
-
sql
|
350
|
-
end
|
351
313
|
|
352
|
-
|
314
|
+
class Integer < Type
|
315
|
+
def type_cast(value)
|
316
|
+
return if value.nil?
|
353
317
|
|
354
|
-
|
355
|
-
|
356
|
-
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
357
|
-
else
|
358
|
-
sql = "SHOW TABLES"
|
318
|
+
value.to_i rescue value ? 1 : 0
|
319
|
+
end
|
359
320
|
end
|
360
321
|
|
361
|
-
|
362
|
-
|
363
|
-
structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n"
|
364
|
-
end
|
365
|
-
end
|
322
|
+
class Date < Type
|
323
|
+
def type; :date; end
|
366
324
|
|
367
|
-
|
368
|
-
|
369
|
-
create_database(name, options)
|
370
|
-
end
|
325
|
+
def type_cast(value)
|
326
|
+
return if value.nil?
|
371
327
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
# create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin'
|
377
|
-
# create_database 'matt_development'
|
378
|
-
# create_database 'matt_development', :charset => :big5
|
379
|
-
def create_database(name, options = {})
|
380
|
-
if options[:collation]
|
381
|
-
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
382
|
-
else
|
383
|
-
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
328
|
+
# FIXME: probably we can improve this since we know it is mysql
|
329
|
+
# specific
|
330
|
+
ConnectionAdapters::Column.value_to_date value
|
331
|
+
end
|
384
332
|
end
|
385
|
-
end
|
386
333
|
|
387
|
-
|
388
|
-
|
389
|
-
end
|
334
|
+
class DateTime < Type
|
335
|
+
def type; :datetime; end
|
390
336
|
|
391
|
-
|
392
|
-
|
393
|
-
end
|
337
|
+
def type_cast(value)
|
338
|
+
return if value.nil?
|
394
339
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
# Returns the database collation strategy.
|
401
|
-
def collation
|
402
|
-
show_variable 'collation_database'
|
403
|
-
end
|
340
|
+
# FIXME: probably we can improve this since we know it is mysql
|
341
|
+
# specific
|
342
|
+
ConnectionAdapters::Column.string_to_time value
|
343
|
+
end
|
344
|
+
end
|
404
345
|
|
405
|
-
|
406
|
-
|
407
|
-
result = execute("SHOW TABLES", name)
|
408
|
-
result.each { |field| tables << field[0] }
|
409
|
-
result.free
|
410
|
-
tables
|
411
|
-
end
|
346
|
+
class Time < Type
|
347
|
+
def type; :time; end
|
412
348
|
|
413
|
-
|
414
|
-
|
415
|
-
end
|
349
|
+
def type_cast(value)
|
350
|
+
return if value.nil?
|
416
351
|
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
|
421
|
-
result.each do |row|
|
422
|
-
if current_index != row[2]
|
423
|
-
next if row[2] == "PRIMARY" # skip the primary key
|
424
|
-
current_index = row[2]
|
425
|
-
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [], [])
|
352
|
+
# FIXME: probably we can improve this since we know it is mysql
|
353
|
+
# specific
|
354
|
+
ConnectionAdapters::Column.string_to_dummy_time value
|
426
355
|
end
|
427
|
-
|
428
|
-
indexes.last.columns << row[4]
|
429
|
-
indexes.last.lengths << row[7]
|
430
356
|
end
|
431
|
-
result.free
|
432
|
-
indexes
|
433
|
-
end
|
434
357
|
|
435
|
-
|
436
|
-
|
437
|
-
columns = []
|
438
|
-
result = execute(sql, :skip_logging)
|
439
|
-
result.each { |field| columns << MysqlColumn.new(field[0], field[4], field[1], field[2] == "YES") }
|
440
|
-
result.free
|
441
|
-
columns
|
442
|
-
end
|
358
|
+
class Float < Type
|
359
|
+
def type; :float; end
|
443
360
|
|
444
|
-
|
445
|
-
|
446
|
-
end
|
361
|
+
def type_cast(value)
|
362
|
+
return if value.nil?
|
447
363
|
|
448
|
-
|
449
|
-
|
450
|
-
|
364
|
+
value.to_f
|
365
|
+
end
|
366
|
+
end
|
451
367
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
add_column_position!(add_column_sql, options)
|
456
|
-
execute(add_column_sql)
|
457
|
-
end
|
368
|
+
class Decimal < Type
|
369
|
+
def type_cast(value)
|
370
|
+
return if value.nil?
|
458
371
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
end
|
372
|
+
ConnectionAdapters::Column.value_to_decimal value
|
373
|
+
end
|
374
|
+
end
|
463
375
|
|
464
|
-
|
465
|
-
|
376
|
+
class Boolean < Type
|
377
|
+
def type_cast(value)
|
378
|
+
return if value.nil?
|
466
379
|
|
467
|
-
|
468
|
-
|
380
|
+
ConnectionAdapters::Column.value_to_boolean value
|
381
|
+
end
|
469
382
|
end
|
470
383
|
|
471
|
-
|
472
|
-
end
|
473
|
-
|
474
|
-
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
475
|
-
column = column_for(table_name, column_name)
|
384
|
+
TYPES = {}
|
476
385
|
|
477
|
-
|
478
|
-
|
386
|
+
# Register an MySQL +type_id+ with a typecasting object in
|
387
|
+
# +type+.
|
388
|
+
def self.register_type(type_id, type)
|
389
|
+
TYPES[type_id] = type
|
479
390
|
end
|
480
391
|
|
481
|
-
|
482
|
-
|
392
|
+
def self.alias_type(new, old)
|
393
|
+
TYPES[new] = TYPES[old]
|
483
394
|
end
|
484
395
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
end
|
396
|
+
register_type Mysql::Field::TYPE_TINY, Fields::Boolean.new
|
397
|
+
register_type Mysql::Field::TYPE_LONG, Fields::Integer.new
|
398
|
+
alias_type Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_LONG
|
399
|
+
alias_type Mysql::Field::TYPE_NEWDECIMAL, Mysql::Field::TYPE_LONG
|
490
400
|
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
|
498
|
-
end
|
499
|
-
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
500
|
-
rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
|
501
|
-
add_column_options!(rename_column_sql, options)
|
502
|
-
execute(rename_column_sql)
|
503
|
-
end
|
401
|
+
register_type Mysql::Field::TYPE_VAR_STRING, Fields::Identity.new
|
402
|
+
register_type Mysql::Field::TYPE_BLOB, Fields::Identity.new
|
403
|
+
register_type Mysql::Field::TYPE_DATE, Fields::Date.new
|
404
|
+
register_type Mysql::Field::TYPE_DATETIME, Fields::DateTime.new
|
405
|
+
register_type Mysql::Field::TYPE_TIME, Fields::Time.new
|
406
|
+
register_type Mysql::Field::TYPE_FLOAT, Fields::Float.new
|
504
407
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
case limit
|
510
|
-
when 1; 'tinyint'
|
511
|
-
when 2; 'smallint'
|
512
|
-
when 3; 'mediumint'
|
513
|
-
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
|
514
|
-
when 5..8; 'bigint'
|
515
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
|
408
|
+
Mysql::Field.constants.grep(/TYPE/).map { |class_name|
|
409
|
+
Mysql::Field.const_get class_name
|
410
|
+
}.reject { |const| TYPES.key? const }.each do |const|
|
411
|
+
register_type const, Fields::Identity.new
|
516
412
|
end
|
517
413
|
end
|
518
414
|
|
519
|
-
def
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
end
|
415
|
+
def exec_without_stmt(sql, name = 'SQL') # :nodoc:
|
416
|
+
# Some queries, like SHOW CREATE TABLE don't work through the prepared
|
417
|
+
# statement API. For those queries, we need to use this method. :'(
|
418
|
+
log(sql, name) do
|
419
|
+
result = @connection.query(sql)
|
420
|
+
affected_rows = @connection.affected_rows
|
526
421
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
422
|
+
if result
|
423
|
+
types = {}
|
424
|
+
result.fetch_fields.each { |field|
|
425
|
+
if field.decimals > 0
|
426
|
+
types[field.name] = Fields::Decimal.new
|
427
|
+
else
|
428
|
+
types[field.name] = Fields::TYPES.fetch(field.type) {
|
429
|
+
Fields::Identity.new
|
430
|
+
}
|
431
|
+
end
|
432
|
+
}
|
433
|
+
result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
|
434
|
+
result.free
|
435
|
+
else
|
436
|
+
result_set = ActiveRecord::Result.new([], [])
|
437
|
+
end
|
532
438
|
|
533
|
-
|
534
|
-
def pk_and_sequence_for(table) #:nodoc:
|
535
|
-
keys = []
|
536
|
-
result = execute("describe #{quote_table_name(table)}")
|
537
|
-
result.each_hash do |h|
|
538
|
-
keys << h["Field"]if h["Key"] == "PRI"
|
439
|
+
[result_set, affected_rows]
|
539
440
|
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def execute_and_free(sql, name = nil)
|
444
|
+
result = execute(sql, name)
|
445
|
+
ret = yield result
|
540
446
|
result.free
|
541
|
-
|
447
|
+
ret
|
542
448
|
end
|
543
449
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
pk_and_sequence && pk_and_sequence.first
|
450
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
451
|
+
super sql, name
|
452
|
+
id_value || @connection.insert_id
|
548
453
|
end
|
454
|
+
alias :create :insert_sql
|
455
|
+
|
456
|
+
def exec_delete(sql, name, binds)
|
457
|
+
affected_rows = 0
|
549
458
|
|
550
|
-
|
551
|
-
|
459
|
+
exec_query(sql, name, binds) do |n|
|
460
|
+
affected_rows = n
|
461
|
+
end
|
462
|
+
|
463
|
+
affected_rows
|
552
464
|
end
|
465
|
+
alias :exec_update :exec_delete
|
553
466
|
|
554
|
-
def
|
555
|
-
|
467
|
+
def begin_db_transaction #:nodoc:
|
468
|
+
exec_query "BEGIN"
|
469
|
+
rescue Mysql::Error
|
470
|
+
# Transactions aren't supported
|
556
471
|
end
|
557
472
|
|
558
|
-
|
559
|
-
def quoted_columns_for_index(column_names, options = {})
|
560
|
-
length = options[:length] if options.is_a?(Hash)
|
473
|
+
private
|
561
474
|
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
475
|
+
def exec_stmt(sql, name, binds)
|
476
|
+
cache = {}
|
477
|
+
log(sql, name, binds) do
|
478
|
+
if binds.empty?
|
479
|
+
stmt = @connection.prepare(sql)
|
567
480
|
else
|
568
|
-
|
481
|
+
cache = @statements[sql] ||= {
|
482
|
+
:stmt => @connection.prepare(sql)
|
483
|
+
}
|
484
|
+
stmt = cache[:stmt]
|
569
485
|
end
|
570
|
-
end
|
571
|
-
|
572
|
-
def translate_exception(exception, message)
|
573
|
-
return super unless exception.respond_to?(:errno)
|
574
486
|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
487
|
+
begin
|
488
|
+
stmt.execute(*binds.map { |col, val| type_cast(val, col) })
|
489
|
+
rescue Mysql::Error => e
|
490
|
+
# Older versions of MySQL leave the prepared statement in a bad
|
491
|
+
# place when an error occurs. To support older mysql versions, we
|
492
|
+
# need to close the statement and delete the statement from the
|
493
|
+
# cache.
|
494
|
+
stmt.close
|
495
|
+
@statements.delete sql
|
496
|
+
raise e
|
582
497
|
end
|
583
|
-
end
|
584
498
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
499
|
+
cols = nil
|
500
|
+
if metadata = stmt.result_metadata
|
501
|
+
cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
|
502
|
+
field.name
|
503
|
+
}
|
590
504
|
end
|
591
505
|
|
592
|
-
|
593
|
-
|
594
|
-
end
|
506
|
+
result_set = ActiveRecord::Result.new(cols, stmt.to_a) if cols
|
507
|
+
affected_rows = stmt.affected_rows
|
595
508
|
|
596
|
-
|
597
|
-
|
598
|
-
|
509
|
+
stmt.result_metadata.free if cols
|
510
|
+
stmt.free_result
|
511
|
+
stmt.close if binds.empty?
|
599
512
|
|
600
|
-
|
513
|
+
[result_set, affected_rows]
|
514
|
+
end
|
515
|
+
end
|
601
516
|
|
602
|
-
|
603
|
-
|
517
|
+
def connect
|
518
|
+
encoding = @config[:encoding]
|
519
|
+
if encoding
|
520
|
+
@connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
|
521
|
+
end
|
604
522
|
|
605
|
-
|
523
|
+
if @config[:sslca] || @config[:sslkey]
|
524
|
+
@connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher])
|
606
525
|
end
|
607
526
|
|
608
|
-
|
609
|
-
|
610
|
-
|
527
|
+
@connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout]
|
528
|
+
@connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout]
|
529
|
+
@connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout]
|
611
530
|
|
612
|
-
|
613
|
-
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
614
|
-
execute("SET SQL_AUTO_IS_NULL=0", :skip_logging)
|
615
|
-
end
|
531
|
+
@connection.real_connect(*@connection_options)
|
616
532
|
|
617
|
-
|
618
|
-
|
619
|
-
result = execute(sql, name)
|
620
|
-
rows = []
|
621
|
-
result.each_hash { |row| rows << row }
|
622
|
-
result.free
|
623
|
-
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
624
|
-
rows
|
625
|
-
end
|
533
|
+
# reconnect must be set after real_connect is called, because real_connect sets it to false internally
|
534
|
+
@connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=)
|
626
535
|
|
627
|
-
|
628
|
-
|
629
|
-
end
|
536
|
+
configure_connection
|
537
|
+
end
|
630
538
|
|
631
|
-
|
632
|
-
|
633
|
-
|
539
|
+
# Many Rails applications monkey-patch a replacement of the configure_connection method
|
540
|
+
# and don't call 'super', so leave this here even though it looks superfluous.
|
541
|
+
def configure_connection
|
542
|
+
super
|
543
|
+
end
|
634
544
|
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
545
|
+
def select(sql, name = nil, binds = [])
|
546
|
+
@connection.query_with_result = true
|
547
|
+
rows = exec_query(sql, name, binds)
|
548
|
+
@connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
|
549
|
+
rows
|
550
|
+
end
|
551
|
+
|
552
|
+
# Returns the version of the connected MySQL server.
|
553
|
+
def version
|
554
|
+
@version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
555
|
+
end
|
641
556
|
end
|
642
557
|
end
|
643
558
|
end
|