activerecord-jdbc-adapter 5.0.pre1 → 50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord-jdbc-adapter might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gitignore +1 -2
- data/.travis.yml +15 -416
- data/Gemfile +35 -37
- data/README.md +23 -118
- data/RUNNING_TESTS.md +31 -26
- data/Rakefile +2 -3
- data/lib/arjdbc/abstract/connection_management.rb +21 -0
- data/lib/arjdbc/abstract/core.rb +62 -0
- data/lib/arjdbc/abstract/database_statements.rb +46 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/derby/adapter.rb +6 -1
- data/lib/arjdbc/discover.rb +0 -7
- data/lib/arjdbc/firebird/adapter.rb +2 -2
- data/lib/arjdbc/jdbc.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +10 -252
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/connection.rb +6 -0
- data/lib/arjdbc/mysql/adapter.rb +82 -946
- data/lib/arjdbc/mysql/connection_methods.rb +4 -2
- data/lib/arjdbc/postgresql/adapter.rb +270 -970
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
- data/lib/arjdbc/postgresql/column.rb +10 -599
- data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +28 -109
- data/lib/arjdbc/sqlite3/adapter.rb +18 -42
- data/lib/arjdbc/tasks/database_tasks.rb +1 -3
- data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +3 -3
- data/rakelib/02-test.rake +0 -12
- data/rakelib/compile.rake +1 -1
- data/rakelib/db.rake +7 -5
- data/rakelib/rails.rake +67 -64
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
- data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
- metadata +16 -29
- data/Appraisals +0 -41
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
- data/lib/arjdbc/common_jdbc_methods.rb +0 -89
- data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
- data/lib/arjdbc/mysql/column.rb +0 -162
- data/lib/arjdbc/mysql/explain_support.rb +0 -82
- data/lib/arjdbc/mysql/schema_creation.rb +0 -58
- data/lib/arjdbc/oracle.rb +0 -4
- data/lib/arjdbc/oracle/adapter.rb +0 -952
- data/lib/arjdbc/oracle/column.rb +0 -126
- data/lib/arjdbc/oracle/connection_methods.rb +0 -21
- data/lib/arjdbc/postgresql/base/oid.rb +0 -412
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
- data/lib/arjdbc/postgresql/explain_support.rb +0 -53
- data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
- data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
- data/src/java/arjdbc/oracle/OracleModule.java +0 -75
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
Binary file
|
@@ -33,6 +33,12 @@ module ActiveRecord
|
|
33
33
|
JdbcTypeConverter.new(supported_data_types).choose_best_types
|
34
34
|
end
|
35
35
|
|
36
|
+
def time_in_default_timezone(value)
|
37
|
+
value = value.to_time if value.respond_to? :to_time
|
38
|
+
|
39
|
+
ActiveRecord::Base::default_timezone == :utc ? value.utc : value.getlocal
|
40
|
+
end
|
41
|
+
|
36
42
|
# @deprecated no longer used - only kept for compatibility
|
37
43
|
def set_native_database_types
|
38
44
|
ArJdbc.deprecate "set_native_database_types is no longer used and does nothing override native_database_types instead"
|
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -1,1001 +1,137 @@
|
|
1
1
|
ArJdbc.load_java_part :MySQL
|
2
2
|
|
3
3
|
require 'bigdecimal'
|
4
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
4
5
|
require 'active_record/connection_adapters/abstract/schema_definitions'
|
6
|
+
require 'arjdbc/abstract/core'
|
7
|
+
require 'arjdbc/abstract/connection_management'
|
8
|
+
require 'arjdbc/abstract/database_statements'
|
9
|
+
require 'arjdbc/abstract/statement_cache'
|
10
|
+
require 'arjdbc/abstract/transaction_support'
|
5
11
|
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
require 'arjdbc/mysql/schema_creation' # AR 4.x
|
13
|
-
|
14
|
-
include BulkChangeTable if const_defined? :BulkChangeTable
|
15
|
-
|
16
|
-
# @private
|
17
|
-
ActiveRecordError = ::ActiveRecord::ActiveRecordError
|
18
|
-
|
19
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
20
|
-
def self.jdbc_connection_class
|
21
|
-
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
22
|
-
end
|
23
|
-
|
24
|
-
def jdbc_column_class
|
25
|
-
::ActiveRecord::ConnectionAdapters::MysqlAdapter::Column
|
26
|
-
end
|
27
|
-
|
28
|
-
# @private
|
29
|
-
def init_connection(jdbc_connection)
|
30
|
-
meta = jdbc_connection.meta_data
|
31
|
-
if meta.driver_major_version == 1 # TODO check in driver code
|
32
|
-
# assumes MariaDB 1.x currently
|
33
|
-
elsif meta.driver_major_version < 5
|
34
|
-
raise ::ActiveRecord::ConnectionNotEstablished,
|
35
|
-
"MySQL adapter requires driver >= 5.0 got: '#{meta.driver_version}'"
|
36
|
-
elsif meta.driver_major_version == 5 && meta.driver_minor_version < 1
|
37
|
-
config[:connection_alive_sql] ||= 'SELECT 1' # need 5.1 for JDBC 4.0
|
38
|
-
else
|
39
|
-
# NOTE: since the loaded Java driver class can't change :
|
40
|
-
MySQL.send(:remove_method, :init_connection) rescue nil
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def configure_connection
|
45
|
-
variables = config[:variables] || {}
|
46
|
-
# By default, MySQL 'where id is null' selects the last inserted id. Turn this off.
|
47
|
-
variables[:sql_auto_is_null] = 0 # execute "SET SQL_AUTO_IS_NULL=0"
|
48
|
-
|
49
|
-
# Increase timeout so the server doesn't disconnect us.
|
50
|
-
wait_timeout = config[:wait_timeout]
|
51
|
-
wait_timeout = self.class.type_cast_config_to_integer(wait_timeout)
|
52
|
-
variables[:wait_timeout] = wait_timeout.is_a?(Fixnum) ? wait_timeout : 2147483
|
53
|
-
|
54
|
-
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
55
|
-
# http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
|
56
|
-
# If the user has provided another value for sql_mode, don't replace it.
|
57
|
-
if strict_mode? && ! variables.has_key?(:sql_mode)
|
58
|
-
variables[:sql_mode] = 'STRICT_ALL_TABLES' # SET SQL_MODE='STRICT_ALL_TABLES'
|
59
|
-
end
|
60
|
-
|
61
|
-
# NAMES does not have an equals sign, see
|
62
|
-
# http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430
|
63
|
-
# (trailing comma because variable_assignments will always have content)
|
64
|
-
encoding = "NAMES #{config[:encoding]}, " if config[:encoding]
|
65
|
-
|
66
|
-
# Gather up all of the SET variables...
|
67
|
-
variable_assignments = variables.map do |k, v|
|
68
|
-
if v == ':default' || v == :default
|
69
|
-
"@@SESSION.#{k.to_s} = DEFAULT" # Sets the value to the global or compile default
|
70
|
-
elsif ! v.nil?
|
71
|
-
"@@SESSION.#{k.to_s} = #{quote(v)}"
|
72
|
-
end
|
73
|
-
# or else nil; compact to clear nils out
|
74
|
-
end.compact.join(', ')
|
75
|
-
|
76
|
-
# ...and send them all in one query
|
77
|
-
execute("SET #{encoding} #{variable_assignments}", :skip_logging)
|
78
|
-
end
|
79
|
-
|
80
|
-
def strict_mode?
|
81
|
-
config.key?(:strict) ?
|
82
|
-
self.class.type_cast_config_to_boolean(config[:strict]) :
|
83
|
-
AR40 # strict_mode is default since AR 4.0
|
84
|
-
end
|
85
|
-
|
86
|
-
# @private
|
87
|
-
@@emulate_booleans = true
|
88
|
-
|
89
|
-
# Boolean emulation can be disabled using (or using the adapter method) :
|
90
|
-
#
|
91
|
-
# ArJdbc::MySQL.emulate_booleans = false
|
92
|
-
#
|
93
|
-
# @see ActiveRecord::ConnectionAdapters::MysqlAdapter#emulate_booleans
|
94
|
-
def self.emulate_booleans?; @@emulate_booleans; end
|
95
|
-
# @deprecated Use {#emulate_booleans?} instead.
|
96
|
-
def self.emulate_booleans; @@emulate_booleans; end
|
97
|
-
# @see #emulate_booleans?
|
98
|
-
def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
|
99
|
-
|
100
|
-
NATIVE_DATABASE_TYPES = {
|
101
|
-
:primary_key => "int(11) auto_increment PRIMARY KEY",
|
102
|
-
:string => { :name => "varchar", :limit => 255 },
|
103
|
-
:text => { :name => "text" },
|
104
|
-
:integer => { :name => "int", :limit => 4 },
|
105
|
-
:float => { :name => "float" },
|
106
|
-
# :double => { :name=>"double", :limit=>17 }
|
107
|
-
# :real => { :name=>"real", :limit=>17 }
|
108
|
-
:numeric => { :name => "numeric" }, # :limit => 65
|
109
|
-
:decimal => { :name => "decimal" }, # :limit => 65
|
110
|
-
:datetime => { :name => "datetime" },
|
111
|
-
# TIMESTAMP has varying properties depending on MySQL version (SQL mode)
|
112
|
-
:timestamp => { :name => "datetime" },
|
113
|
-
:time => { :name => "time" },
|
114
|
-
:date => { :name => "date" },
|
115
|
-
:binary => { :name => "blob" },
|
116
|
-
:boolean => { :name => "tinyint", :limit => 1 },
|
117
|
-
# AR-JDBC added :
|
118
|
-
:bit => { :name => "bit" }, # :limit => 1
|
119
|
-
:enum => { :name => "enum" },
|
120
|
-
:set => { :name => "set" }, # :limit => 64
|
121
|
-
:char => { :name => "char" }, # :limit => 255
|
122
|
-
}
|
123
|
-
|
124
|
-
# @override
|
125
|
-
def native_database_types
|
126
|
-
NATIVE_DATABASE_TYPES
|
127
|
-
end
|
128
|
-
|
129
|
-
ADAPTER_NAME = 'MySQL'.freeze
|
130
|
-
|
131
|
-
# @override
|
132
|
-
def adapter_name
|
133
|
-
ADAPTER_NAME
|
134
|
-
end
|
135
|
-
|
136
|
-
def case_sensitive_equality_operator
|
137
|
-
"= BINARY"
|
138
|
-
end
|
139
|
-
|
140
|
-
def case_sensitive_modifier(node)
|
141
|
-
Arel::Nodes::Bin.new(node)
|
142
|
-
end unless AR42
|
143
|
-
|
144
|
-
def case_sensitive_modifier(node, table_attribute)
|
145
|
-
node = Arel::Nodes.build_quoted node, table_attribute
|
146
|
-
Arel::Nodes::Bin.new(node)
|
147
|
-
end if AR42
|
148
|
-
|
149
|
-
def case_sensitive_comparison(table, attribute, column, value)
|
150
|
-
if column.case_sensitive?
|
151
|
-
table[attribute].eq(value)
|
152
|
-
else
|
153
|
-
super
|
154
|
-
end
|
155
|
-
end if AR42
|
156
|
-
|
157
|
-
def case_insensitive_comparison(table, attribute, column, value)
|
158
|
-
if column.case_sensitive?
|
159
|
-
super
|
160
|
-
else
|
161
|
-
table[attribute].eq(value)
|
162
|
-
end
|
163
|
-
end if AR42
|
164
|
-
|
165
|
-
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
|
166
|
-
where_sql
|
167
|
-
end
|
168
|
-
|
169
|
-
def initialize_schema_migrations_table
|
170
|
-
if @config[:encoding] == 'utf8mb4'
|
171
|
-
ActiveRecord::SchemaMigration.create_table(191)
|
172
|
-
else
|
173
|
-
ActiveRecord::SchemaMigration.create_table
|
174
|
-
end
|
175
|
-
end if AR40
|
176
|
-
|
177
|
-
# HELPER METHODS ===========================================
|
178
|
-
|
179
|
-
# @private Only for Rails core compatibility.
|
180
|
-
def new_column(field, default, type, null, collation, extra = "")
|
181
|
-
jdbc_column_class.new(field, default, type, null, collation, strict_mode?, extra)
|
182
|
-
end unless AR42
|
183
|
-
|
184
|
-
# @private Only for Rails core compatibility.
|
185
|
-
def new_column(field, default, cast_type, sql_type = nil, null = true, collation = "", extra = "")
|
186
|
-
jdbc_column_class.new(field, default, cast_type, sql_type, null, collation, strict_mode?, extra)
|
187
|
-
end if AR42
|
188
|
-
|
189
|
-
# @private Only for Rails core compatibility.
|
190
|
-
def error_number(exception)
|
191
|
-
exception.error_code if exception.respond_to?(:error_code)
|
192
|
-
end
|
193
|
-
|
194
|
-
# QUOTING ==================================================
|
195
|
-
|
196
|
-
# @override
|
197
|
-
def quote(value, column = nil)
|
198
|
-
return value.quoted_id if value.respond_to?(:quoted_id)
|
199
|
-
return value if sql_literal?(value)
|
200
|
-
return value.to_s if column && column.type == :primary_key
|
201
|
-
|
202
|
-
if value.kind_of?(String) && column && column.type == :binary
|
203
|
-
"x'#{value.unpack("H*")[0]}'"
|
204
|
-
elsif value.kind_of?(BigDecimal)
|
205
|
-
value.to_s("F")
|
206
|
-
else
|
207
|
-
super
|
208
|
-
end
|
209
|
-
end unless AR42
|
210
|
-
|
211
|
-
# @private since AR 4.2
|
212
|
-
def _quote(value)
|
213
|
-
if value.is_a?(Type::Binary::Data)
|
214
|
-
"x'#{value.hex}'"
|
215
|
-
else
|
216
|
-
super
|
217
|
-
end
|
218
|
-
end if AR42
|
219
|
-
|
220
|
-
# @override
|
221
|
-
def quote_column_name(name)
|
222
|
-
"`#{name.to_s.gsub('`', '``')}`"
|
223
|
-
end
|
224
|
-
|
225
|
-
# @override
|
226
|
-
def quote_table_name(name)
|
227
|
-
quote_column_name(name).gsub('.', '`.`')
|
228
|
-
end
|
229
|
-
|
230
|
-
# @override
|
231
|
-
def supports_migrations?
|
232
|
-
true
|
233
|
-
end
|
234
|
-
|
235
|
-
# @override
|
236
|
-
def supports_primary_key?
|
237
|
-
true
|
238
|
-
end
|
239
|
-
|
240
|
-
# @override
|
241
|
-
def supports_index_sort_order?
|
242
|
-
# Technically MySQL allows to create indexes with the sort order syntax
|
243
|
-
# but at the moment (5.5) it doesn't yet implement them.
|
244
|
-
true
|
245
|
-
end
|
246
|
-
|
247
|
-
# @override
|
248
|
-
def supports_indexes_in_create?
|
249
|
-
true
|
250
|
-
end
|
251
|
-
|
252
|
-
# @override
|
253
|
-
def supports_transaction_isolation?
|
254
|
-
# MySQL 4 technically support transaction isolation, but it is affected by
|
255
|
-
# a bug where the transaction level gets persisted for the whole session:
|
256
|
-
# http://bugs.mysql.com/bug.php?id=39170
|
257
|
-
version[0] && version[0] >= 5
|
258
|
-
end
|
259
|
-
|
260
|
-
# @override
|
261
|
-
def supports_views?
|
262
|
-
version[0] && version[0] >= 5
|
263
|
-
end
|
264
|
-
|
265
|
-
def supports_rename_index?
|
266
|
-
return false if mariadb? || ! version[0]
|
267
|
-
(version[0] == 5 && version[1] >= 7) || version[0] >= 6
|
268
|
-
end
|
269
|
-
|
270
|
-
def index_algorithms
|
271
|
-
{ :default => 'ALGORITHM = DEFAULT', :copy => 'ALGORITHM = COPY', :inplace => 'ALGORITHM = INPLACE' }
|
272
|
-
end if AR42
|
273
|
-
|
274
|
-
# @override
|
275
|
-
def supports_transaction_isolation?(level = nil)
|
276
|
-
version[0] && version[0] >= 5 # MySQL 5+
|
277
|
-
end
|
278
|
-
|
279
|
-
# NOTE: handled by JdbcAdapter only to have statements in logs :
|
280
|
-
|
281
|
-
# @override
|
282
|
-
def supports_savepoints?
|
283
|
-
true
|
284
|
-
end
|
285
|
-
|
286
|
-
# @override
|
287
|
-
def create_savepoint(name = current_savepoint_name(true))
|
288
|
-
log("SAVEPOINT #{name}", 'Savepoint') { super }
|
289
|
-
end
|
290
|
-
|
291
|
-
# @override
|
292
|
-
def rollback_to_savepoint(name = current_savepoint_name(true))
|
293
|
-
log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { super }
|
294
|
-
end
|
295
|
-
|
296
|
-
# @override
|
297
|
-
def release_savepoint(name = current_savepoint_name(false))
|
298
|
-
log("RELEASE SAVEPOINT #{name}", 'Savepoint') { super }
|
299
|
-
end
|
300
|
-
|
301
|
-
def disable_referential_integrity
|
302
|
-
fk_checks = select_value("SELECT @@FOREIGN_KEY_CHECKS")
|
303
|
-
begin
|
304
|
-
update("SET FOREIGN_KEY_CHECKS = 0")
|
305
|
-
yield
|
306
|
-
ensure
|
307
|
-
update("SET FOREIGN_KEY_CHECKS = #{fk_checks}")
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
# @override make it public just like native MySQL adapter does
|
312
|
-
def update_sql(sql, name = nil)
|
313
|
-
super
|
314
|
-
end
|
315
|
-
|
316
|
-
# SCHEMA STATEMENTS ========================================
|
317
|
-
|
318
|
-
# @deprecated no longer used - handled with (AR built-in) Rake tasks
|
319
|
-
def structure_dump
|
320
|
-
# NOTE: due AR (2.3-3.2) compatibility views are not included
|
321
|
-
if supports_views?
|
322
|
-
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
323
|
-
else
|
324
|
-
sql = "SHOW TABLES"
|
325
|
-
end
|
326
|
-
|
327
|
-
@connection.execute_query_raw(sql).map do |table|
|
328
|
-
# e.g. { "Tables_in_arjdbc_test"=>"big_fields", "Table_type"=>"BASE TABLE" }
|
329
|
-
table.delete('Table_type')
|
330
|
-
table_name = table.to_a.first.last
|
331
|
-
|
332
|
-
create_table = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")
|
333
|
-
|
334
|
-
"#{create_table['Create Table']};\n\n"
|
335
|
-
end.join
|
336
|
-
end
|
337
|
-
|
338
|
-
# Returns just a table's primary key.
|
339
|
-
# @override
|
340
|
-
def primary_key(table)
|
341
|
-
#pk_and_sequence = pk_and_sequence_for(table)
|
342
|
-
#pk_and_sequence && pk_and_sequence.first
|
343
|
-
@connection.primary_keys(table).first
|
344
|
-
end
|
345
|
-
|
346
|
-
# Returns a table's primary key and belonging sequence.
|
347
|
-
# @note Not used, only here for potential compatibility with native adapter.
|
348
|
-
# @override
|
349
|
-
def pk_and_sequence_for(table)
|
350
|
-
result = execute("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA').first
|
351
|
-
if result['Create Table'].to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
|
352
|
-
keys = $1.split(","); keys.map! { |key| key.gsub(/[`"]/, "") }
|
353
|
-
return keys.length == 1 ? [ keys.first, nil ] : nil
|
354
|
-
else
|
355
|
-
return nil
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
# @private
|
360
|
-
IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
|
361
|
-
|
362
|
-
INDEX_TYPES = [ :fulltext, :spatial ] if AR40
|
363
|
-
INDEX_USINGS = [ :btree, :hash ] if AR40
|
364
|
-
|
365
|
-
# Returns an array of indexes for the given table.
|
366
|
-
# @override
|
367
|
-
def indexes(table_name, name = nil)
|
368
|
-
indexes = []
|
369
|
-
current_index = nil
|
370
|
-
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name || 'SCHEMA')
|
371
|
-
result.each do |row|
|
372
|
-
key_name = row['Key_name']
|
373
|
-
if current_index != key_name
|
374
|
-
next if key_name == 'PRIMARY' # skip the primary key
|
375
|
-
current_index = key_name
|
376
|
-
indexes <<
|
377
|
-
if self.class.const_defined?(:INDEX_TYPES) # AR 4.0
|
378
|
-
mysql_index_type = row['Index_type'].downcase.to_sym
|
379
|
-
index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
|
380
|
-
index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
|
381
|
-
IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [], nil, nil, index_type, index_using)
|
382
|
-
else
|
383
|
-
IndexDefinition.new(row['Table'], key_name, row['Non_unique'].to_i == 0, [], [])
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
indexes.last.columns << row["Column_name"]
|
388
|
-
indexes.last.lengths << row["Sub_part"]
|
389
|
-
end
|
390
|
-
indexes
|
391
|
-
end
|
392
|
-
|
393
|
-
# Returns an array of `Column` objects for the table specified.
|
394
|
-
# @override
|
395
|
-
def columns(table_name, name = nil)
|
396
|
-
sql = "SHOW FULL #{AR40 ? 'FIELDS' : 'COLUMNS'} FROM #{quote_table_name(table_name)}"
|
397
|
-
columns = execute(sql, name || 'SCHEMA')
|
398
|
-
strict = strict_mode?
|
399
|
-
pass_cast_type = respond_to?(:lookup_cast_type)
|
400
|
-
columns.map! do |field|
|
401
|
-
sql_type = field['Type']
|
402
|
-
null = field['Null'] == "YES"
|
403
|
-
if pass_cast_type
|
404
|
-
cast_type = lookup_cast_type(sql_type)
|
405
|
-
jdbc_column_class.new(field['Field'], field['Default'], cast_type, sql_type, null, field['Collation'], strict, field['Extra'])
|
406
|
-
else
|
407
|
-
jdbc_column_class.new(field['Field'], field['Default'], sql_type, null, field['Collation'], strict, field['Extra'])
|
408
|
-
end
|
409
|
-
end
|
410
|
-
columns
|
411
|
-
end
|
412
|
-
|
413
|
-
if defined? ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
|
414
|
-
|
415
|
-
class SchemaCreation < ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
|
416
|
-
|
417
|
-
# @private
|
418
|
-
def visit_AddColumn(o)
|
419
|
-
add_column_position!(super, column_options(o))
|
420
|
-
end
|
421
|
-
|
422
|
-
# @private re-defined since AR 4.1
|
423
|
-
def visit_ChangeColumnDefinition(o)
|
424
|
-
column = o.column
|
425
|
-
options = o.options
|
426
|
-
sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale])
|
427
|
-
change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}"
|
428
|
-
add_column_options!(change_column_sql, options.merge(:column => column))
|
429
|
-
add_column_position!(change_column_sql, options)
|
430
|
-
end
|
431
|
-
|
432
|
-
# @private since AR 4.2
|
433
|
-
def visit_DropForeignKey(name)
|
434
|
-
"DROP FOREIGN KEY #{name}"
|
435
|
-
end
|
436
|
-
|
437
|
-
# @private since AR 4.2
|
438
|
-
def visit_TableDefinition(o)
|
439
|
-
name = o.name
|
440
|
-
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(name)} "
|
441
|
-
|
442
|
-
statements = o.columns.map { |c| accept c }
|
443
|
-
statements.concat(o.indexes.map { |column_name, options| index_in_create(name, column_name, options) })
|
444
|
-
|
445
|
-
create_sql << "(#{statements.join(', ')}) " if statements.present?
|
446
|
-
create_sql << "#{o.options}"
|
447
|
-
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
448
|
-
create_sql
|
449
|
-
end if AR42
|
450
|
-
|
451
|
-
private
|
452
|
-
|
453
|
-
def add_column_position!(sql, options)
|
454
|
-
if options[:first]
|
455
|
-
sql << " FIRST"
|
456
|
-
elsif options[:after]
|
457
|
-
sql << " AFTER #{quote_column_name(options[:after])}"
|
458
|
-
end
|
459
|
-
sql
|
460
|
-
end
|
461
|
-
|
462
|
-
def column_options(o)
|
463
|
-
column_options = {}
|
464
|
-
column_options[:null] = o.null unless o.null.nil?
|
465
|
-
column_options[:default] = o.default unless o.default.nil?
|
466
|
-
column_options[:column] = o
|
467
|
-
column_options[:first] = o.first
|
468
|
-
column_options[:after] = o.after
|
469
|
-
column_options
|
470
|
-
end
|
471
|
-
|
472
|
-
def index_in_create(table_name, column_name, options)
|
473
|
-
index_name, index_type, index_columns, index_options, index_algorithm, index_using = @conn.add_index_options(table_name, column_name, options)
|
474
|
-
"#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_options} #{index_algorithm}"
|
475
|
-
end
|
476
|
-
|
477
|
-
end
|
478
|
-
|
479
|
-
def schema_creation; SchemaCreation.new self end
|
480
|
-
|
481
|
-
end
|
482
|
-
|
483
|
-
# @private
|
484
|
-
def recreate_database(name, options = {})
|
485
|
-
drop_database(name)
|
486
|
-
create_database(name, options)
|
487
|
-
reconnect!
|
488
|
-
end
|
489
|
-
|
490
|
-
# @override
|
491
|
-
def create_database(name, options = {})
|
492
|
-
if options[:collation]
|
493
|
-
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
494
|
-
else
|
495
|
-
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
# @override
|
500
|
-
def drop_database(name)
|
501
|
-
execute "DROP DATABASE IF EXISTS `#{name}`"
|
502
|
-
end
|
503
|
-
|
504
|
-
def current_database
|
505
|
-
select_one("SELECT DATABASE() as db")['db']
|
506
|
-
end
|
507
|
-
|
508
|
-
def truncate(table_name, name = nil)
|
509
|
-
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
|
510
|
-
end
|
511
|
-
|
512
|
-
# @override
|
513
|
-
def create_table(name, options = {})
|
514
|
-
super(name, { :options => "ENGINE=InnoDB" }.merge(options))
|
515
|
-
end
|
516
|
-
|
517
|
-
def drop_table(table_name, options = {})
|
518
|
-
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
|
519
|
-
end
|
520
|
-
|
521
|
-
# @override
|
522
|
-
def rename_table(table_name, new_name)
|
523
|
-
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
524
|
-
rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
|
525
|
-
end
|
526
|
-
|
527
|
-
# @override
|
528
|
-
def remove_index!(table_name, index_name)
|
529
|
-
# missing table_name quoting in AR-2.3
|
530
|
-
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
531
|
-
end
|
532
|
-
|
533
|
-
# @override
|
534
|
-
def rename_index(table_name, old_name, new_name)
|
535
|
-
if supports_rename_index?
|
536
|
-
validate_index_length!(table_name, new_name) if respond_to?(:validate_index_length!)
|
537
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
|
538
|
-
else
|
539
|
-
super
|
540
|
-
end
|
541
|
-
end
|
542
|
-
|
543
|
-
# @private
|
544
|
-
ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition if ::ActiveRecord::ConnectionAdapters.const_defined? :ForeignKeyDefinition
|
545
|
-
|
546
|
-
# @override
|
547
|
-
def supports_foreign_keys?; true end
|
548
|
-
|
549
|
-
def foreign_keys(table_name)
|
550
|
-
fk_info = select_all "" <<
|
551
|
-
"SELECT fk.referenced_table_name as 'to_table' " <<
|
552
|
-
",fk.referenced_column_name as 'primary_key' " <<
|
553
|
-
",fk.column_name as 'column' " <<
|
554
|
-
",fk.constraint_name as 'name' " <<
|
555
|
-
"FROM information_schema.key_column_usage fk " <<
|
556
|
-
"WHERE fk.referenced_column_name is not null " <<
|
557
|
-
"AND fk.table_schema = '#{current_database}' " <<
|
558
|
-
"AND fk.table_name = '#{table_name}'"
|
559
|
-
|
560
|
-
create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
|
561
|
-
|
562
|
-
fk_info.map! do |row|
|
563
|
-
options = {
|
564
|
-
:column => row['column'], :name => row['name'], :primary_key => row['primary_key']
|
565
|
-
}
|
566
|
-
options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
|
567
|
-
options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
|
568
|
-
|
569
|
-
ForeignKeyDefinition.new(table_name, row['to_table'], options)
|
570
|
-
end
|
571
|
-
end if defined? ForeignKeyDefinition
|
572
|
-
|
573
|
-
def extract_foreign_key_action(structure, name, action)
|
574
|
-
if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
|
575
|
-
case $1
|
576
|
-
when 'CASCADE'; :cascade
|
577
|
-
when 'SET NULL'; :nullify
|
578
|
-
end
|
579
|
-
end
|
12
|
+
module ActiveRecord
|
13
|
+
class ConnectionAdapters::AbstractMysqlAdapter
|
14
|
+
# FIXME: this is to work around abstract mysql having 4 arity but core wants to pass 3
|
15
|
+
# FIXME: Missing the logic from original module.
|
16
|
+
def initialize(connection, logger, config)
|
17
|
+
super(connection, logger, config)
|
580
18
|
end
|
581
|
-
|
582
|
-
|
583
|
-
#
|
584
|
-
|
585
|
-
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
586
|
-
add_column_options!(add_column_sql, options)
|
587
|
-
add_column_position!(add_column_sql, options)
|
588
|
-
execute(add_column_sql)
|
589
|
-
end unless const_defined? :SchemaCreation
|
590
|
-
|
591
|
-
def change_column_default(table_name, column_name, default)
|
592
|
-
column = column_for(table_name, column_name)
|
593
|
-
change_column table_name, column_name, column.sql_type, :default => default
|
594
|
-
end # unless const_defined? :SchemaCreation
|
19
|
+
end
|
20
|
+
module ConnectionAdapters
|
21
|
+
# Remove any vestiges of core/Ruby MySQL adapter
|
22
|
+
remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
|
595
23
|
|
596
|
-
|
597
|
-
|
24
|
+
class Mysql2Adapter < AbstractMysqlAdapter
|
25
|
+
ADAPTER_NAME = 'Mysql2'.freeze
|
598
26
|
|
599
|
-
|
600
|
-
|
601
|
-
|
27
|
+
include ArJdbc::Abstract::Core
|
28
|
+
include ArJdbc::Abstract::ConnectionManagement
|
29
|
+
include ArJdbc::Abstract::DatabaseStatements
|
30
|
+
include ArJdbc::Abstract::StatementCache
|
31
|
+
include ArJdbc::Abstract::TransactionSupport
|
602
32
|
|
603
|
-
|
604
|
-
|
33
|
+
def initialize(connection, logger, connection_options, config)
|
34
|
+
super(connection, logger, config)
|
605
35
|
|
606
|
-
|
607
|
-
def change_column(table_name, column_name, type, options = {})
|
608
|
-
column = column_for(table_name, column_name)
|
36
|
+
@prepared_statements = false unless config.key?(:prepared_statements)
|
609
37
|
|
610
|
-
|
611
|
-
# NOTE: no defaults for BLOB/TEXT columns with MySQL
|
612
|
-
options[:default] = column.default if type != :text && type != :binary
|
38
|
+
configure_connection
|
613
39
|
end
|
614
40
|
|
615
|
-
|
616
|
-
|
41
|
+
def supports_json?
|
42
|
+
!mariadb? && version >= '5.7.8'
|
617
43
|
end
|
618
44
|
|
619
|
-
|
620
|
-
|
621
|
-
add_column_position!(change_column_sql, options)
|
622
|
-
execute(change_column_sql)
|
623
|
-
end
|
624
|
-
|
625
|
-
# @private
|
626
|
-
def change_column(table_name, column_name, type, options = {})
|
627
|
-
execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")
|
628
|
-
end if AR42
|
629
|
-
|
630
|
-
# @override
|
631
|
-
def rename_column(table_name, column_name, new_column_name)
|
632
|
-
options = {}
|
633
|
-
|
634
|
-
if column = columns(table_name).find { |c| c.name == column_name.to_s }
|
635
|
-
type = column.type
|
636
|
-
options[:default] = column.default if type != :text && type != :binary
|
637
|
-
options[:null] = column.null
|
638
|
-
else
|
639
|
-
raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
|
45
|
+
def supports_comments?
|
46
|
+
true
|
640
47
|
end
|
641
48
|
|
642
|
-
|
643
|
-
|
644
|
-
rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
|
645
|
-
add_column_options!(rename_column_sql, options)
|
646
|
-
execute(rename_column_sql)
|
647
|
-
rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
|
648
|
-
end
|
649
|
-
|
650
|
-
def add_column_position!(sql, options)
|
651
|
-
if options[:first]
|
652
|
-
sql << " FIRST"
|
653
|
-
elsif options[:after]
|
654
|
-
sql << " AFTER #{quote_column_name(options[:after])}"
|
655
|
-
end
|
656
|
-
end unless const_defined? :SchemaCreation
|
657
|
-
|
658
|
-
# @note Only used with (non-AREL) ActiveRecord **2.3**.
|
659
|
-
# @see Arel::Visitors::MySQL
|
660
|
-
def add_limit_offset!(sql, options)
|
661
|
-
limit, offset = options[:limit], options[:offset]
|
662
|
-
if limit && offset
|
663
|
-
sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}"
|
664
|
-
elsif limit
|
665
|
-
sql << " LIMIT #{sanitize_limit(limit)}"
|
666
|
-
elsif offset
|
667
|
-
sql << " OFFSET #{offset.to_i}"
|
49
|
+
def supports_comments_in_create?
|
50
|
+
true
|
668
51
|
end
|
669
|
-
sql
|
670
|
-
end if ::ActiveRecord::VERSION::MAJOR < 3
|
671
|
-
|
672
|
-
# In the simple case, MySQL allows us to place JOINs directly into the UPDATE
|
673
|
-
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
674
|
-
# these, we must use a subquery. However, MySQL is too stupid to create a
|
675
|
-
# temporary table for this automatically, so we have to give it some prompting
|
676
|
-
# in the form of a subsubquery. Ugh!
|
677
|
-
# @private based on mysql_adapter.rb from 3.1-stable
|
678
|
-
def join_to_update(update, select)
|
679
|
-
if select.limit || select.offset || select.orders.any?
|
680
|
-
subsubselect = select.clone
|
681
|
-
subsubselect.projections = [update.key]
|
682
52
|
|
683
|
-
|
684
|
-
|
685
|
-
subselect.from subsubselect.as('__active_record_temp')
|
686
|
-
|
687
|
-
update.where update.key.in(subselect)
|
688
|
-
else
|
689
|
-
update.table select.source
|
690
|
-
update.wheres = select.constraints
|
53
|
+
def supports_savepoints?
|
54
|
+
true
|
691
55
|
end
|
692
|
-
end
|
693
56
|
|
694
|
-
|
695
|
-
res = execute("show variables like '#{var}'")
|
696
|
-
result_row = res.detect {|row| row["Variable_name"] == var }
|
697
|
-
result_row && result_row["Value"]
|
698
|
-
end
|
699
|
-
|
700
|
-
def charset
|
701
|
-
show_variable("character_set_database")
|
702
|
-
end
|
703
|
-
|
704
|
-
def collation
|
705
|
-
show_variable("collation_database")
|
706
|
-
end
|
57
|
+
# HELPER METHODS ===========================================
|
707
58
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
when 'binary'
|
712
|
-
case limit
|
713
|
-
when 0..0xfff; "varbinary(#{limit})"
|
714
|
-
when nil; "blob"
|
715
|
-
when 0x1000..0xffffffff; "blob(#{limit})"
|
716
|
-
else raise(ActiveRecordError, "No binary type has character length #{limit}")
|
717
|
-
end
|
718
|
-
when 'integer'
|
719
|
-
case limit
|
720
|
-
when 1; 'tinyint'
|
721
|
-
when 2; 'smallint'
|
722
|
-
when 3; 'mediumint'
|
723
|
-
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
|
724
|
-
when 5..8; 'bigint'
|
725
|
-
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
|
726
|
-
end
|
727
|
-
when 'text'
|
728
|
-
case limit
|
729
|
-
when 0..0xff; 'tinytext'
|
730
|
-
when nil, 0x100..0xffff; 'text'
|
731
|
-
when 0x10000..0xffffff; 'mediumtext'
|
732
|
-
when 0x1000000..0xffffffff; 'longtext'
|
733
|
-
else raise(ActiveRecordError, "No text type has character length #{limit}")
|
734
|
-
end
|
735
|
-
when 'datetime'
|
736
|
-
return super unless precision
|
737
|
-
|
738
|
-
case precision
|
739
|
-
when 0..6; "datetime(#{precision})"
|
740
|
-
else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
|
741
|
-
end
|
742
|
-
else
|
59
|
+
# Reloading the type map in abstract/statement_cache.rb blows up postgres
|
60
|
+
def clear_cache!
|
61
|
+
reload_type_map
|
743
62
|
super
|
744
63
|
end
|
745
|
-
end
|
746
|
-
|
747
|
-
# @override
|
748
|
-
def empty_insert_statement_value
|
749
|
-
"VALUES ()"
|
750
|
-
end
|
751
|
-
|
752
|
-
# @note since AR 4.2
|
753
|
-
def valid_type?(type)
|
754
|
-
! native_database_types[type].nil?
|
755
|
-
end
|
756
|
-
|
757
|
-
def clear_cache!
|
758
|
-
super
|
759
|
-
reload_type_map
|
760
|
-
end if AR42
|
761
|
-
|
762
|
-
# @private since AR 4.2
|
763
|
-
def prepare_column_options(column, types)
|
764
|
-
spec = super
|
765
|
-
spec.delete(:limit) if column.type == :boolean
|
766
|
-
spec
|
767
|
-
end if AR42
|
768
64
|
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
register_class_with_limit m, %r(char)i, MysqlString
|
779
|
-
|
780
|
-
m.register_type %r(tinytext)i, Type::Text.new(:limit => 2**8 - 1)
|
781
|
-
m.register_type %r(tinyblob)i, Type::Binary.new(:limit => 2**8 - 1)
|
782
|
-
m.register_type %r(text)i, Type::Text.new(:limit => 2**16 - 1)
|
783
|
-
m.register_type %r(blob)i, Type::Binary.new(:limit => 2**16 - 1)
|
784
|
-
m.register_type %r(mediumtext)i, Type::Text.new(:limit => 2**24 - 1)
|
785
|
-
m.register_type %r(mediumblob)i, Type::Binary.new(:limit => 2**24 - 1)
|
786
|
-
m.register_type %r(longtext)i, Type::Text.new(:limit => 2**32 - 1)
|
787
|
-
m.register_type %r(longblob)i, Type::Binary.new(:limit => 2**32 - 1)
|
788
|
-
m.register_type %r(^float)i, Type::Float.new(:limit => 24)
|
789
|
-
m.register_type %r(^double)i, Type::Float.new(:limit => 53)
|
790
|
-
|
791
|
-
register_integer_type m, %r(^bigint)i, :limit => 8
|
792
|
-
register_integer_type m, %r(^int)i, :limit => 4
|
793
|
-
register_integer_type m, %r(^mediumint)i, :limit => 3
|
794
|
-
register_integer_type m, %r(^smallint)i, :limit => 2
|
795
|
-
register_integer_type m, %r(^tinyint)i, :limit => 1
|
796
|
-
|
797
|
-
m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
|
798
|
-
m.alias_type %r(set)i, 'varchar'
|
799
|
-
m.alias_type %r(year)i, 'integer'
|
800
|
-
m.alias_type %r(bit)i, 'binary'
|
801
|
-
|
802
|
-
m.register_type(%r(datetime)i) do |sql_type|
|
803
|
-
precision = extract_precision(sql_type)
|
804
|
-
MysqlDateTime.new(:precision => precision)
|
805
|
-
end
|
806
|
-
|
807
|
-
m.register_type(%r(enum)i) do |sql_type|
|
808
|
-
limit = sql_type[/^enum\((.+)\)/i, 1].split(',').
|
809
|
-
map{|enum| enum.strip.length - 2}.max
|
810
|
-
MysqlString.new(:limit => limit)
|
811
|
-
end
|
812
|
-
end if AR42
|
813
|
-
|
814
|
-
# @private
|
815
|
-
def register_integer_type(mapping, key, options)
|
816
|
-
mapping.register_type(key) do |sql_type|
|
817
|
-
if /unsigned/i =~ sql_type
|
818
|
-
Type::UnsignedInteger.new(options)
|
65
|
+
def each_hash(result) # :nodoc:
|
66
|
+
if block_given?
|
67
|
+
# FIXME: This is C in mysql2 gem and I just made simplest Ruby
|
68
|
+
result.each do |row|
|
69
|
+
new_hash = {}
|
70
|
+
row.each { |k, v| new_hash[k.to_sym] = v }
|
71
|
+
yield new_hash
|
72
|
+
end
|
819
73
|
else
|
820
|
-
|
74
|
+
to_enum(:each_hash, result)
|
821
75
|
end
|
822
76
|
end
|
823
|
-
end if AR42
|
824
|
-
|
825
|
-
# MySQL is too stupid to create a temporary table for use subquery, so we have
|
826
|
-
# to give it some prompting in the form of a subsubquery. Ugh!
|
827
|
-
# @note since AR 4.2
|
828
|
-
def subquery_for(key, select)
|
829
|
-
subsubselect = select.clone
|
830
|
-
subsubselect.projections = [key]
|
831
|
-
|
832
|
-
subselect = Arel::SelectManager.new(select.engine)
|
833
|
-
subselect.project Arel.sql(key.name)
|
834
|
-
subselect.from subsubselect.as('__active_record_temp')
|
835
|
-
end if AR42
|
836
|
-
|
837
|
-
def quoted_columns_for_index(column_names, options = {})
|
838
|
-
length = options[:length] if options.is_a?(Hash)
|
839
|
-
|
840
|
-
case length
|
841
|
-
when Hash
|
842
|
-
column_names.map { |name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) }
|
843
|
-
when Fixnum
|
844
|
-
column_names.map { |name| "#{quote_column_name(name)}(#{length})" }
|
845
|
-
else
|
846
|
-
column_names.map { |name| quote_column_name(name) }
|
847
|
-
end
|
848
|
-
end
|
849
|
-
|
850
|
-
# @override
|
851
|
-
def translate_exception(exception, message)
|
852
|
-
return super unless exception.respond_to?(:errno)
|
853
|
-
|
854
|
-
case exception.errno
|
855
|
-
when 1062
|
856
|
-
::ActiveRecord::RecordNotUnique.new(message, exception)
|
857
|
-
when 1452
|
858
|
-
::ActiveRecord::InvalidForeignKey.new(message, exception)
|
859
|
-
else
|
860
|
-
super
|
861
|
-
end
|
862
|
-
end
|
863
|
-
|
864
|
-
private
|
865
|
-
|
866
|
-
def column_for(table_name, column_name)
|
867
|
-
unless column = columns(table_name).find { |c| c.name == column_name.to_s }
|
868
|
-
raise "No such column: #{table_name}.#{column_name}"
|
869
|
-
end
|
870
|
-
column
|
871
|
-
end
|
872
77
|
|
873
|
-
|
874
|
-
|
875
|
-
def version
|
876
|
-
return @version ||= begin
|
877
|
-
version = []
|
878
|
-
java_connection = jdbc_connection(true)
|
879
|
-
if java_connection.java_class.name == 'com.mysql.jdbc.ConnectionImpl'
|
880
|
-
version << jdbc_connection.serverMajorVersion
|
881
|
-
version << jdbc_connection.serverMinorVersion
|
882
|
-
version << jdbc_connection.serverSubMinorVersion
|
883
|
-
else
|
884
|
-
if match = full_version.match(/^(\d+)\.(\d+)\.(\d+)/)
|
885
|
-
version << match[1].to_i
|
886
|
-
version << match[2].to_i
|
887
|
-
version << match[3].to_i
|
888
|
-
end
|
889
|
-
end
|
890
|
-
version.freeze
|
78
|
+
def error_number(exception)
|
79
|
+
exception.errno if exception.respond_to? :errno
|
891
80
|
end
|
892
|
-
end
|
893
81
|
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
|
82
|
+
# FIXME: #833 This is wrong...it should not always pass utf8 and native adapter never does...
|
83
|
+
def create_table(table_name, **options) #:nodoc:
|
84
|
+
super(table_name, options: 'ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci', **options)
|
898
85
|
end
|
899
|
-
end
|
900
86
|
|
901
|
-
|
902
|
-
|
903
|
-
|
87
|
+
#--
|
88
|
+
# QUOTING ==================================================
|
89
|
+
#++
|
904
90
|
|
905
|
-
|
906
|
-
|
907
|
-
private
|
908
|
-
|
909
|
-
def has_precision?
|
910
|
-
precision || 0
|
91
|
+
def quote_string(string)
|
92
|
+
string.gsub(/[\x00\n\r\\\'\"]/, '\\\\\0')
|
911
93
|
end
|
912
|
-
end if AR42
|
913
94
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
95
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
96
|
+
last_id = if without_prepared_statement?(binds)
|
97
|
+
log(sql, name) { @connection.execute_insert(sql) }
|
98
|
+
else
|
99
|
+
log(sql, name, binds) { @connection.execute_insert(sql, binds) }
|
100
|
+
end
|
101
|
+
# FIXME: execute_insert and executeUpdate mapping key results is very varied and I am wondering
|
102
|
+
# if AR is now much more consistent. I worked around by manually making a result here.
|
103
|
+
::ActiveRecord::Result.new(nil, [[last_id]])
|
922
104
|
end
|
105
|
+
alias insert_sql exec_insert
|
106
|
+
deprecate insert_sql: :insert
|
923
107
|
|
924
108
|
private
|
925
109
|
|
926
|
-
def
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
else super
|
110
|
+
def full_version
|
111
|
+
@full_version ||= begin
|
112
|
+
result = execute 'SELECT VERSION()', 'SCHEMA'
|
113
|
+
result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
|
931
114
|
end
|
932
115
|
end
|
933
|
-
end if AR42
|
934
|
-
|
935
|
-
end
|
936
|
-
end
|
937
|
-
|
938
|
-
module ActiveRecord
|
939
|
-
module ConnectionAdapters
|
940
|
-
# Remove any vestiges of core/Ruby MySQL adapter
|
941
|
-
remove_const(:MysqlAdapter) if const_defined?(:MysqlAdapter)
|
942
|
-
|
943
|
-
class MysqlAdapter < JdbcAdapter
|
944
|
-
include ::ArJdbc::MySQL
|
945
|
-
include ::ArJdbc::MySQL::ExplainSupport
|
946
|
-
|
947
|
-
def arel_visitor # :nodoc:
|
948
|
-
Arel::Visitors::MySQL.new(self)
|
949
|
-
end
|
950
|
-
|
951
|
-
# By default, the MysqlAdapter will consider all columns of type
|
952
|
-
# __tinyint(1)__ as boolean. If you wish to disable this :
|
953
|
-
# ```
|
954
|
-
# ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
|
955
|
-
# ```
|
956
|
-
def self.emulate_booleans?; ::ArJdbc::MySQL.emulate_booleans?; end
|
957
|
-
def self.emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end # native adapter
|
958
|
-
def self.emulate_booleans=(emulate); ::ArJdbc::MySQL.emulate_booleans = emulate; end
|
959
|
-
|
960
|
-
class Column < JdbcColumn
|
961
|
-
include ::ArJdbc::MySQL::Column
|
962
|
-
|
963
|
-
# @note {#ArJdbc::MySQL::Column} uses this to check for boolean emulation
|
964
|
-
def adapter
|
965
|
-
MysqlAdapter
|
966
|
-
end
|
967
|
-
|
968
|
-
end
|
969
|
-
|
970
|
-
#def initialize(*args)
|
971
|
-
# super # configure_connection happens in super
|
972
|
-
#end
|
973
116
|
|
974
117
|
def jdbc_connection_class(spec)
|
975
|
-
::
|
118
|
+
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
976
119
|
end
|
977
120
|
|
978
121
|
def jdbc_column_class
|
979
|
-
Column
|
122
|
+
::ActiveRecord::ConnectionAdapters::MySQL::Column
|
980
123
|
end
|
981
124
|
|
982
125
|
end
|
126
|
+
end
|
983
127
|
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
if ActiveRecord::VERSION::MAJOR > 3 ||
|
991
|
-
( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR >= 1 )
|
992
|
-
remove_const(:Mysql2Adapter) if const_defined?(:Mysql2Adapter)
|
993
|
-
Mysql2Adapter = MysqlAdapter
|
994
|
-
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 1
|
995
|
-
remove_const(:Mysql2Column) if const_defined?(:Mysql2Column)
|
996
|
-
Mysql2Column = MysqlAdapter::Column
|
128
|
+
# FIXME: #834 Not sure how this is scoped or whether we should use it or just alias it to our
|
129
|
+
# JDBCError.
|
130
|
+
class ::Mysql2
|
131
|
+
class Error < Exception
|
132
|
+
def initialize(*)
|
133
|
+
super("error")
|
997
134
|
end
|
998
135
|
end
|
999
|
-
|
1000
136
|
end
|
1001
137
|
end
|