activerecord-jdbc-adapter 5.0.pre1 → 51.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.
- 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/activerecord-jdbc-adapter.gemspec +1 -2
- 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/adapter.rb +10 -252
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/connection.rb +6 -0
- data/lib/arjdbc/jdbc.rb +2 -2
- data/lib/arjdbc/mysql/adapter.rb +87 -944
- data/lib/arjdbc/mysql/connection_methods.rb +4 -2
- data/lib/arjdbc/postgresql/adapter.rb +288 -1023
- 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 +25 -110
- data/lib/arjdbc/sqlite3/adapter.rb +171 -170
- 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 +63 -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 +20 -34
- 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/adapter.rb +0 -952
- data/lib/arjdbc/oracle/column.rb +0 -126
- data/lib/arjdbc/oracle/connection_methods.rb +0 -21
- data/lib/arjdbc/oracle.rb +0 -4
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.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
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -1,1001 +1,144 @@
|
|
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}"
|
640
|
-
end
|
641
|
-
|
642
|
-
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
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])}"
|
45
|
+
def supports_comments?
|
46
|
+
true
|
655
47
|
end
|
656
|
-
end unless const_defined? :SchemaCreation
|
657
48
|
|
658
|
-
|
659
|
-
|
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
|
-
|
694
|
-
def show_variable(var)
|
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
|
707
56
|
|
708
|
-
|
709
|
-
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
710
|
-
case type.to_s
|
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
|
57
|
+
# HELPER METHODS ===========================================
|
737
58
|
|
738
|
-
|
739
|
-
|
740
|
-
|
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
|
-
|
769
|
-
# @private
|
770
|
-
Type = ActiveRecord::Type if AR42
|
771
|
-
|
772
|
-
protected
|
773
|
-
|
774
|
-
# @private
|
775
|
-
def initialize_type_map(m)
|
776
|
-
super
|
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
64
|
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
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
77
|
|
850
|
-
|
851
|
-
|
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
|
78
|
+
def error_number(exception)
|
79
|
+
exception.errno if exception.respond_to? :errno
|
861
80
|
end
|
862
|
-
end
|
863
|
-
|
864
|
-
private
|
865
81
|
|
866
|
-
|
867
|
-
|
868
|
-
|
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)
|
869
85
|
end
|
870
|
-
column
|
871
|
-
end
|
872
86
|
|
873
|
-
|
87
|
+
#--
|
88
|
+
# QUOTING ==================================================
|
89
|
+
#+
|
874
90
|
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
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
|
91
|
+
# FIXME: 5.1 crashes without this. I think this is Arel hitting a fallback path in to_sql.rb.
|
92
|
+
# So maybe an untested code path in their source. Still means we are doing something wrong to
|
93
|
+
# even hit it.
|
94
|
+
def quote(value, comment=nil)
|
95
|
+
super(value)
|
891
96
|
end
|
892
|
-
end
|
893
97
|
|
894
|
-
|
895
|
-
|
896
|
-
result = execute 'SELECT VERSION()', 'SCHEMA'
|
897
|
-
result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
|
98
|
+
def quote_string(string)
|
99
|
+
string.gsub(/[\x00\n\r\\\'\"]/, '\\\\\0')
|
898
100
|
end
|
899
|
-
end
|
900
|
-
|
901
|
-
# @private
|
902
|
-
def emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end # due AR 4.2
|
903
|
-
public :emulate_booleans
|
904
|
-
|
905
|
-
# @private
|
906
|
-
class MysqlDateTime < Type::DateTime
|
907
|
-
private
|
908
101
|
|
909
|
-
def
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
when true then "1"
|
919
|
-
when false then "0"
|
920
|
-
else super
|
921
|
-
end
|
102
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
103
|
+
last_id = if without_prepared_statement?(binds)
|
104
|
+
log(sql, name) { @connection.execute_insert(sql) }
|
105
|
+
else
|
106
|
+
log(sql, name, binds) { @connection.execute_insert(sql, binds) }
|
107
|
+
end
|
108
|
+
# FIXME: execute_insert and executeUpdate mapping key results is very varied and I am wondering
|
109
|
+
# if AR is now much more consistent. I worked around by manually making a result here.
|
110
|
+
::ActiveRecord::Result.new(nil, [[last_id]])
|
922
111
|
end
|
112
|
+
alias insert_sql exec_insert
|
113
|
+
deprecate insert_sql: :insert
|
923
114
|
|
924
115
|
private
|
925
116
|
|
926
|
-
def
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
else super
|
117
|
+
def full_version
|
118
|
+
@full_version ||= begin
|
119
|
+
result = execute 'SELECT VERSION()', 'SCHEMA'
|
120
|
+
result.first.values.first # [{"VERSION()"=>"5.5.37-0ubuntu..."}]
|
931
121
|
end
|
932
122
|
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
123
|
|
974
124
|
def jdbc_connection_class(spec)
|
975
|
-
::
|
125
|
+
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
976
126
|
end
|
977
127
|
|
978
128
|
def jdbc_column_class
|
979
|
-
Column
|
129
|
+
::ActiveRecord::ConnectionAdapters::MySQL::Column
|
980
130
|
end
|
981
131
|
|
982
132
|
end
|
133
|
+
end
|
983
134
|
|
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
|
135
|
+
# FIXME: #834 Not sure how this is scoped or whether we should use it or just alias it to our
|
136
|
+
# JDBCError.
|
137
|
+
class ::Mysql2
|
138
|
+
class Error < Exception
|
139
|
+
def initialize(*)
|
140
|
+
super("error")
|
997
141
|
end
|
998
142
|
end
|
999
|
-
|
1000
143
|
end
|
1001
144
|
end
|