activerecord 5.0.0.beta3 → 5.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +225 -8
- data/examples/performance.rb +0 -1
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/associations.rb +10 -6
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +1 -1
- data/lib/active_record/associations/preloader.rb +1 -0
- data/lib/active_record/associations/preloader/through_association.rb +15 -8
- data/lib/active_record/attribute/user_provided_default.rb +10 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +1 -1
- data/lib/active_record/base.rb +2 -1
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -19
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -8
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -4
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +20 -10
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +85 -20
- data/lib/active_record/connection_adapters/abstract/transaction.rb +13 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -16
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +119 -108
- data/lib/active_record/connection_adapters/column.rb +5 -6
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +27 -6
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -55
- data/lib/active_record/connection_adapters/postgresql/column.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +7 -10
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +65 -25
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +59 -30
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +19 -56
- data/lib/active_record/connection_adapters/statement_pool.rb +6 -4
- data/lib/active_record/core.rb +13 -4
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/errors.rb +9 -0
- data/lib/active_record/fixture_set/file.rb +7 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +4 -0
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +1 -1
- data/lib/active_record/model_schema.rb +12 -0
- data/lib/active_record/nested_attributes.rb +1 -1
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/query_cache.rb +13 -16
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +8 -11
- data/lib/active_record/railties/databases.rake +5 -5
- data/lib/active_record/reflection.rb +21 -4
- data/lib/active_record/relation.rb +10 -10
- data/lib/active_record/relation/batches.rb +29 -9
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +27 -8
- data/lib/active_record/relation/predicate_builder.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +2 -1
- data/lib/active_record/schema_dumper.rb +39 -24
- data/lib/active_record/scoping/default.rb +2 -1
- data/lib/active_record/suppressor.rb +5 -1
- data/lib/active_record/tasks/database_tasks.rb +6 -4
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/type.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +1 -5
- data/lib/active_record/type/time.rb +12 -0
- data/lib/active_record/validations/uniqueness.rb +1 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -11
- data/lib/rails/generators/active_record/model/templates/application_record.rb +2 -0
- metadata +11 -8
@@ -188,7 +188,10 @@ module ActiveRecord
|
|
188
188
|
transaction = begin_transaction options
|
189
189
|
yield
|
190
190
|
rescue Exception => error
|
191
|
-
|
191
|
+
if transaction
|
192
|
+
rollback_transaction
|
193
|
+
after_failure_actions(transaction, error)
|
194
|
+
end
|
192
195
|
raise
|
193
196
|
ensure
|
194
197
|
unless error
|
@@ -214,7 +217,16 @@ module ActiveRecord
|
|
214
217
|
end
|
215
218
|
|
216
219
|
private
|
220
|
+
|
217
221
|
NULL_TRANSACTION = NullTransaction.new
|
222
|
+
|
223
|
+
# Deallocate invalidated prepared statements outside of the transaction
|
224
|
+
def after_failure_actions(transaction, error)
|
225
|
+
return unless transaction.is_a?(RealTransaction)
|
226
|
+
return unless error.is_a?(ActiveRecord::PreparedStatementCacheExpired)
|
227
|
+
@connection.clear_cache!
|
228
|
+
end
|
229
|
+
|
218
230
|
end
|
219
231
|
end
|
220
232
|
end
|
@@ -27,7 +27,6 @@ module ActiveRecord
|
|
27
27
|
|
28
28
|
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
|
29
29
|
autoload :ConnectionHandler
|
30
|
-
autoload :ConnectionManagement
|
31
30
|
end
|
32
31
|
|
33
32
|
autoload_under 'abstract' do
|
@@ -68,6 +67,7 @@ module ActiveRecord
|
|
68
67
|
include QueryCache
|
69
68
|
include ActiveSupport::Callbacks
|
70
69
|
include ColumnDumper
|
70
|
+
include Savepoints
|
71
71
|
|
72
72
|
SIMPLE_INT = /\A\d+\z/
|
73
73
|
|
@@ -105,8 +105,15 @@ module ActiveRecord
|
|
105
105
|
@config = config
|
106
106
|
@pool = nil
|
107
107
|
@schema_cache = SchemaCache.new self
|
108
|
-
@
|
109
|
-
@
|
108
|
+
@quoted_column_names, @quoted_table_names = {}, {}
|
109
|
+
@visitor = arel_visitor
|
110
|
+
|
111
|
+
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
112
|
+
@prepared_statements = true
|
113
|
+
@visitor.extend(DetermineIfPreparableVisitor)
|
114
|
+
else
|
115
|
+
@prepared_statements = false
|
116
|
+
end
|
110
117
|
end
|
111
118
|
|
112
119
|
class Version
|
@@ -142,8 +149,12 @@ module ActiveRecord
|
|
142
149
|
end
|
143
150
|
end
|
144
151
|
|
152
|
+
def arel_visitor # :nodoc:
|
153
|
+
Arel::Visitors::ToSql.new(self)
|
154
|
+
end
|
155
|
+
|
145
156
|
def valid_type?(type)
|
146
|
-
|
157
|
+
false
|
147
158
|
end
|
148
159
|
|
149
160
|
def schema_creation
|
@@ -237,6 +248,11 @@ module ActiveRecord
|
|
237
248
|
false
|
238
249
|
end
|
239
250
|
|
251
|
+
# Does this adapter support expression indices?
|
252
|
+
def supports_expression_index?
|
253
|
+
false
|
254
|
+
end
|
255
|
+
|
240
256
|
# Does this adapter support explain?
|
241
257
|
def supports_explain?
|
242
258
|
false
|
@@ -278,6 +294,21 @@ module ActiveRecord
|
|
278
294
|
false
|
279
295
|
end
|
280
296
|
|
297
|
+
# Does this adapter support metadata comments on database objects (tables, columns, indexes)?
|
298
|
+
def supports_comments?
|
299
|
+
false
|
300
|
+
end
|
301
|
+
|
302
|
+
# Can comments for tables, columns, and indexes be specified in create/alter table statements?
|
303
|
+
def supports_comments_in_create?
|
304
|
+
false
|
305
|
+
end
|
306
|
+
|
307
|
+
# Does this adapter support multi-value insert?
|
308
|
+
def supports_multi_insert?
|
309
|
+
true
|
310
|
+
end
|
311
|
+
|
281
312
|
# This is meant to be implemented by the adapters that support extensions
|
282
313
|
def disable_extension(name)
|
283
314
|
end
|
@@ -379,12 +410,6 @@ module ActiveRecord
|
|
379
410
|
@connection
|
380
411
|
end
|
381
412
|
|
382
|
-
def create_savepoint(name = nil)
|
383
|
-
end
|
384
|
-
|
385
|
-
def release_savepoint(name = nil)
|
386
|
-
end
|
387
|
-
|
388
413
|
def case_sensitive_comparison(table, attribute, column, value)
|
389
414
|
if value.nil?
|
390
415
|
table[attribute].eq(value)
|
@@ -406,10 +431,6 @@ module ActiveRecord
|
|
406
431
|
end
|
407
432
|
private :can_perform_case_insensitive_comparison_for?
|
408
433
|
|
409
|
-
def current_savepoint_name
|
410
|
-
current_transaction.savepoint_name
|
411
|
-
end
|
412
|
-
|
413
434
|
# Check the connection back in to the connection pool
|
414
435
|
def close
|
415
436
|
pool.checkin self
|
@@ -421,8 +442,8 @@ module ActiveRecord
|
|
421
442
|
end
|
422
443
|
end
|
423
444
|
|
424
|
-
def new_column(name, default, sql_type_metadata
|
425
|
-
Column.new(name, default, sql_type_metadata, null, default_function, collation)
|
445
|
+
def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
|
446
|
+
Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
|
426
447
|
end
|
427
448
|
|
428
449
|
def lookup_cast_type(sql_type) # :nodoc:
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
+
require 'active_record/connection_adapters/statement_pool'
|
2
3
|
require 'active_record/connection_adapters/mysql/column'
|
3
4
|
require 'active_record/connection_adapters/mysql/explain_pretty_printer'
|
5
|
+
require 'active_record/connection_adapters/mysql/quoting'
|
4
6
|
require 'active_record/connection_adapters/mysql/schema_creation'
|
5
7
|
require 'active_record/connection_adapters/mysql/schema_definitions'
|
6
8
|
require 'active_record/connection_adapters/mysql/schema_dumper'
|
@@ -11,8 +13,8 @@ require 'active_support/core_ext/string/strip'
|
|
11
13
|
module ActiveRecord
|
12
14
|
module ConnectionAdapters
|
13
15
|
class AbstractMysqlAdapter < AbstractAdapter
|
16
|
+
include MySQL::Quoting
|
14
17
|
include MySQL::ColumnDumper
|
15
|
-
include Savepoints
|
16
18
|
|
17
19
|
def update_table_definition(table_name, base) # :nodoc:
|
18
20
|
MySQL::Table.new(table_name, base)
|
@@ -22,6 +24,10 @@ module ActiveRecord
|
|
22
24
|
MySQL::SchemaCreation.new(self)
|
23
25
|
end
|
24
26
|
|
27
|
+
def arel_visitor # :nodoc:
|
28
|
+
Arel::Visitors::MySQL.new(self)
|
29
|
+
end
|
30
|
+
|
25
31
|
##
|
26
32
|
# :singleton-method:
|
27
33
|
# By default, the Mysql2Adapter will consider all columns of type <tt>tinyint(1)</tt>
|
@@ -32,8 +38,6 @@ module ActiveRecord
|
|
32
38
|
class_attribute :emulate_booleans
|
33
39
|
self.emulate_booleans = true
|
34
40
|
|
35
|
-
QUOTED_TRUE, QUOTED_FALSE = '1', '0'
|
36
|
-
|
37
41
|
NATIVE_DATABASE_TYPES = {
|
38
42
|
primary_key: "int auto_increment PRIMARY KEY",
|
39
43
|
string: { name: "varchar", limit: 255 },
|
@@ -52,18 +56,16 @@ module ActiveRecord
|
|
52
56
|
INDEX_TYPES = [:fulltext, :spatial]
|
53
57
|
INDEX_USINGS = [:btree, :hash]
|
54
58
|
|
59
|
+
class StatementPool < ConnectionAdapters::StatementPool
|
60
|
+
private def dealloc(stmt)
|
61
|
+
stmt[:stmt].close
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
55
65
|
def initialize(connection, logger, connection_options, config)
|
56
66
|
super(connection, logger, config)
|
57
|
-
@quoted_column_names, @quoted_table_names = {}, {}
|
58
67
|
|
59
|
-
@
|
60
|
-
|
61
|
-
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
62
|
-
@prepared_statements = true
|
63
|
-
@visitor.extend(DetermineIfPreparableVisitor)
|
64
|
-
else
|
65
|
-
@prepared_statements = false
|
66
|
-
end
|
68
|
+
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
67
69
|
|
68
70
|
if version < '5.0.0'
|
69
71
|
raise "Your version of MySQL (#{full_version.match(/^\d+\.\d+\.\d+/)[0]}) is too old. Active Record supports MySQL >= 5.0."
|
@@ -78,10 +80,14 @@ module ActiveRecord
|
|
78
80
|
}
|
79
81
|
end
|
80
82
|
|
81
|
-
def version
|
83
|
+
def version #:nodoc:
|
82
84
|
@version ||= Version.new(full_version.match(/^\d+\.\d+\.\d+/)[0])
|
83
85
|
end
|
84
86
|
|
87
|
+
def mariadb? # :nodoc:
|
88
|
+
full_version =~ /mariadb/i
|
89
|
+
end
|
90
|
+
|
85
91
|
# Returns true, since this connection adapter supports migrations.
|
86
92
|
def supports_migrations?
|
87
93
|
true
|
@@ -95,6 +101,12 @@ module ActiveRecord
|
|
95
101
|
true
|
96
102
|
end
|
97
103
|
|
104
|
+
# Returns true, since this connection adapter supports prepared statement
|
105
|
+
# caching.
|
106
|
+
def supports_statement_cache?
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
98
110
|
# Technically MySQL allows to create indexes with the sort order syntax
|
99
111
|
# but at the moment (5.5) it doesn't yet implement them
|
100
112
|
def supports_index_sort_order?
|
@@ -122,7 +134,11 @@ module ActiveRecord
|
|
122
134
|
end
|
123
135
|
|
124
136
|
def supports_datetime_with_precision?
|
125
|
-
|
137
|
+
if mariadb?
|
138
|
+
version >= '5.3.0'
|
139
|
+
else
|
140
|
+
version >= '5.6.4'
|
141
|
+
end
|
126
142
|
end
|
127
143
|
|
128
144
|
def supports_advisory_locks?
|
@@ -153,8 +169,8 @@ module ActiveRecord
|
|
153
169
|
raise NotImplementedError
|
154
170
|
end
|
155
171
|
|
156
|
-
def new_column(
|
157
|
-
MySQL::Column.new(
|
172
|
+
def new_column(*args) #:nodoc:
|
173
|
+
MySQL::Column.new(*args)
|
158
174
|
end
|
159
175
|
|
160
176
|
# Must return the MySQL error number from the exception, if the exception has an
|
@@ -163,48 +179,6 @@ module ActiveRecord
|
|
163
179
|
raise NotImplementedError
|
164
180
|
end
|
165
181
|
|
166
|
-
# QUOTING ==================================================
|
167
|
-
|
168
|
-
def _quote(value) # :nodoc:
|
169
|
-
if value.is_a?(Type::Binary::Data)
|
170
|
-
"x'#{value.hex}'"
|
171
|
-
else
|
172
|
-
super
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def quote_column_name(name) #:nodoc:
|
177
|
-
@quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
|
178
|
-
end
|
179
|
-
|
180
|
-
def quote_table_name(name) #:nodoc:
|
181
|
-
@quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
|
182
|
-
end
|
183
|
-
|
184
|
-
def quoted_true
|
185
|
-
QUOTED_TRUE
|
186
|
-
end
|
187
|
-
|
188
|
-
def unquoted_true
|
189
|
-
1
|
190
|
-
end
|
191
|
-
|
192
|
-
def quoted_false
|
193
|
-
QUOTED_FALSE
|
194
|
-
end
|
195
|
-
|
196
|
-
def unquoted_false
|
197
|
-
0
|
198
|
-
end
|
199
|
-
|
200
|
-
def quoted_date(value)
|
201
|
-
if supports_datetime_with_precision?
|
202
|
-
super
|
203
|
-
else
|
204
|
-
super.sub(/\.\d{6}\z/, '')
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
182
|
# REFERENTIAL INTEGRITY ====================================
|
209
183
|
|
210
184
|
def disable_referential_integrity #:nodoc:
|
@@ -218,6 +192,14 @@ module ActiveRecord
|
|
218
192
|
end
|
219
193
|
end
|
220
194
|
|
195
|
+
# CONNECTION MANAGEMENT ====================================
|
196
|
+
|
197
|
+
# Clears the prepared statements cache.
|
198
|
+
def clear_cache!
|
199
|
+
reload_type_map
|
200
|
+
@statements.clear
|
201
|
+
end
|
202
|
+
|
221
203
|
#--
|
222
204
|
# DATABASE STATEMENTS ======================================
|
223
205
|
#++
|
@@ -231,11 +213,6 @@ module ActiveRecord
|
|
231
213
|
MySQL::ExplainPrettyPrinter.new.pp(result, elapsed)
|
232
214
|
end
|
233
215
|
|
234
|
-
def clear_cache!
|
235
|
-
super
|
236
|
-
reload_type_map
|
237
|
-
end
|
238
|
-
|
239
216
|
# Executes the SQL statement in the context of this connection.
|
240
217
|
def execute(sql, name = nil)
|
241
218
|
log(sql, name) { @connection.query(sql) }
|
@@ -301,9 +278,9 @@ module ActiveRecord
|
|
301
278
|
# create_database 'matt_development', charset: :big5
|
302
279
|
def create_database(name, options = {})
|
303
280
|
if options[:collation]
|
304
|
-
execute "CREATE DATABASE
|
281
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset] || 'utf8')} COLLATE #{quote_table_name(options[:collation])}"
|
305
282
|
else
|
306
|
-
execute "CREATE DATABASE
|
283
|
+
execute "CREATE DATABASE #{quote_table_name(name)} DEFAULT CHARACTER SET #{quote_table_name(options[:charset] || 'utf8')}"
|
307
284
|
end
|
308
285
|
end
|
309
286
|
|
@@ -312,7 +289,7 @@ module ActiveRecord
|
|
312
289
|
# Example:
|
313
290
|
# drop_database('sebastian_development')
|
314
291
|
def drop_database(name) #:nodoc:
|
315
|
-
execute "DROP DATABASE IF EXISTS
|
292
|
+
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
316
293
|
end
|
317
294
|
|
318
295
|
def current_database
|
@@ -370,8 +347,7 @@ module ActiveRecord
|
|
370
347
|
def data_source_exists?(table_name)
|
371
348
|
return false unless table_name.present?
|
372
349
|
|
373
|
-
schema, name = table_name
|
374
|
-
schema, name = @config[:database], schema unless name # A table was provided without a schema
|
350
|
+
schema, name = extract_schema_qualified_name(table_name)
|
375
351
|
|
376
352
|
sql = "SELECT table_name FROM information_schema.tables "
|
377
353
|
sql << "WHERE table_schema = #{quote(schema)} AND table_name = #{quote(name)}"
|
@@ -386,8 +362,7 @@ module ActiveRecord
|
|
386
362
|
def view_exists?(view_name) # :nodoc:
|
387
363
|
return false unless view_name.present?
|
388
364
|
|
389
|
-
schema, name = view_name
|
390
|
-
schema, name = @config[:database], schema unless name # A view was provided without a schema
|
365
|
+
schema, name = extract_schema_qualified_name(view_name)
|
391
366
|
|
392
367
|
sql = "SELECT table_name FROM information_schema.tables WHERE table_type = 'VIEW'"
|
393
368
|
sql << " AND table_schema = #{quote(schema)} AND table_name = #{quote(name)}"
|
@@ -408,7 +383,7 @@ module ActiveRecord
|
|
408
383
|
mysql_index_type = row[:Index_type].downcase.to_sym
|
409
384
|
index_type = INDEX_TYPES.include?(mysql_index_type) ? mysql_index_type : nil
|
410
385
|
index_using = INDEX_USINGS.include?(mysql_index_type) ? mysql_index_type : nil
|
411
|
-
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], [], nil, nil, index_type, index_using)
|
386
|
+
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique].to_i == 0, [], [], nil, nil, index_type, index_using, row[:Index_comment].presence)
|
412
387
|
end
|
413
388
|
|
414
389
|
indexes.last.columns << row[:Column_name]
|
@@ -421,21 +396,28 @@ module ActiveRecord
|
|
421
396
|
|
422
397
|
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
423
398
|
def columns(table_name) # :nodoc:
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
new_column(field[:Field], field[:Default], type_metadata, field[:Null] == "YES", nil, field[:Collation])
|
432
|
-
end
|
399
|
+
table_name = table_name.to_s
|
400
|
+
column_definitions(table_name).map do |field|
|
401
|
+
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
402
|
+
if type_metadata.type == :datetime && field[:Default] == "CURRENT_TIMESTAMP"
|
403
|
+
default, default_function = nil, field[:Default]
|
404
|
+
else
|
405
|
+
default, default_function = field[:Default], nil
|
433
406
|
end
|
407
|
+
new_column(field[:Field], default, type_metadata, field[:Null] == "YES", table_name, default_function, field[:Collation], comment: field[:Comment].presence)
|
434
408
|
end
|
435
409
|
end
|
436
410
|
|
437
|
-
def
|
438
|
-
|
411
|
+
def table_comment(table_name) # :nodoc:
|
412
|
+
select_value(<<-SQL.strip_heredoc, 'SCHEMA')
|
413
|
+
SELECT table_comment
|
414
|
+
FROM information_schema.tables
|
415
|
+
WHERE table_name=#{quote(table_name)}
|
416
|
+
SQL
|
417
|
+
end
|
418
|
+
|
419
|
+
def create_table(table_name, **options) #:nodoc:
|
420
|
+
super(table_name, options: 'ENGINE=InnoDB', **options)
|
439
421
|
end
|
440
422
|
|
441
423
|
def bulk_change_table(table_name, operations) #:nodoc:
|
@@ -518,11 +500,17 @@ module ActiveRecord
|
|
518
500
|
end
|
519
501
|
|
520
502
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
521
|
-
index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
|
522
|
-
|
503
|
+
index_name, index_type, index_columns, _, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
504
|
+
sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns}) #{index_algorithm}"
|
505
|
+
sql << " COMMENT #{quote(comment)}" if comment
|
506
|
+
execute sql
|
523
507
|
end
|
524
508
|
|
525
509
|
def foreign_keys(table_name)
|
510
|
+
raise ArgumentError unless table_name.present?
|
511
|
+
|
512
|
+
schema, name = extract_schema_qualified_name(table_name)
|
513
|
+
|
526
514
|
fk_info = select_all <<-SQL.strip_heredoc
|
527
515
|
SELECT fk.referenced_table_name as 'to_table'
|
528
516
|
,fk.referenced_column_name as 'primary_key'
|
@@ -530,8 +518,8 @@ module ActiveRecord
|
|
530
518
|
,fk.constraint_name as 'name'
|
531
519
|
FROM information_schema.key_column_usage fk
|
532
520
|
WHERE fk.referenced_column_name is not null
|
533
|
-
AND fk.table_schema =
|
534
|
-
AND fk.table_name =
|
521
|
+
AND fk.table_schema = #{quote(schema)}
|
522
|
+
AND fk.table_name = #{quote(name)}
|
535
523
|
SQL
|
536
524
|
|
537
525
|
create_table_info = create_table_info(table_name)
|
@@ -557,7 +545,12 @@ module ActiveRecord
|
|
557
545
|
raw_table_options = create_table_info.sub(/\A.*\n\) /m, '').sub(/\n\/\*!.*\*\/\n\z/m, '').strip
|
558
546
|
|
559
547
|
# strip AUTO_INCREMENT
|
560
|
-
raw_table_options.sub(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
548
|
+
raw_table_options.sub!(/(ENGINE=\w+)(?: AUTO_INCREMENT=\d+)/, '\1')
|
549
|
+
|
550
|
+
# strip COMMENT
|
551
|
+
raw_table_options.sub!(/ COMMENT='.+'/, '')
|
552
|
+
|
553
|
+
raw_table_options
|
561
554
|
end
|
562
555
|
|
563
556
|
# Maps logical Rails types to MySQL-specific data types.
|
@@ -585,8 +578,7 @@ module ActiveRecord
|
|
585
578
|
|
586
579
|
# SHOW VARIABLES LIKE 'name'
|
587
580
|
def show_variable(name)
|
588
|
-
|
589
|
-
variables.first['Value'] unless variables.empty?
|
581
|
+
select_value("SELECT @@#{name}", 'SCHEMA')
|
590
582
|
rescue ActiveRecord::StatementInvalid
|
591
583
|
nil
|
592
584
|
end
|
@@ -594,8 +586,7 @@ module ActiveRecord
|
|
594
586
|
def primary_keys(table_name) # :nodoc:
|
595
587
|
raise ArgumentError unless table_name.present?
|
596
588
|
|
597
|
-
schema, name = table_name
|
598
|
-
schema, name = @config[:database], schema unless name # A table was provided without a schema
|
589
|
+
schema, name = extract_schema_qualified_name(table_name)
|
599
590
|
|
600
591
|
select_values(<<-SQL.strip_heredoc, 'SCHEMA')
|
601
592
|
SELECT column_name
|
@@ -608,10 +599,10 @@ module ActiveRecord
|
|
608
599
|
end
|
609
600
|
|
610
601
|
def case_sensitive_comparison(table, attribute, column, value)
|
611
|
-
if value.nil?
|
612
|
-
super
|
613
|
-
else
|
602
|
+
if !value.nil? && column.collation && !column.case_sensitive?
|
614
603
|
table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
|
604
|
+
else
|
605
|
+
super
|
615
606
|
end
|
616
607
|
end
|
617
608
|
|
@@ -668,7 +659,7 @@ module ActiveRecord
|
|
668
659
|
register_integer_type m, %r(^smallint)i, limit: 2
|
669
660
|
register_integer_type m, %r(^tinyint)i, limit: 1
|
670
661
|
|
671
|
-
m.
|
662
|
+
m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
|
672
663
|
m.alias_type %r(year)i, 'integer'
|
673
664
|
m.alias_type %r(bit)i, 'binary'
|
674
665
|
|
@@ -738,6 +729,8 @@ module ActiveRecord
|
|
738
729
|
RecordNotUnique.new(message)
|
739
730
|
when 1452
|
740
731
|
InvalidForeignKey.new(message)
|
732
|
+
when 1406
|
733
|
+
ValueTooLong.new(message)
|
741
734
|
else
|
742
735
|
super
|
743
736
|
end
|
@@ -823,10 +816,6 @@ module ActiveRecord
|
|
823
816
|
subselect.from subsubselect.as('__active_record_temp')
|
824
817
|
end
|
825
818
|
|
826
|
-
def mariadb?
|
827
|
-
full_version =~ /mariadb/i
|
828
|
-
end
|
829
|
-
|
830
819
|
def supports_rename_index?
|
831
820
|
mariadb? ? false : version >= '5.7.6'
|
832
821
|
end
|
@@ -847,9 +836,19 @@ module ActiveRecord
|
|
847
836
|
# Make MySQL reject illegal values rather than truncating or blanking them, see
|
848
837
|
# http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
|
849
838
|
# If the user has provided another value for sql_mode, don't replace it.
|
850
|
-
|
851
|
-
|
839
|
+
if sql_mode = variables.delete('sql_mode')
|
840
|
+
sql_mode = quote(sql_mode)
|
841
|
+
elsif !defaults.include?(strict_mode?)
|
842
|
+
if strict_mode?
|
843
|
+
sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
|
844
|
+
else
|
845
|
+
sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
|
846
|
+
sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
|
847
|
+
sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
|
848
|
+
end
|
849
|
+
sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
|
852
850
|
end
|
851
|
+
sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
|
853
852
|
|
854
853
|
# NAMES does not have an equals sign, see
|
855
854
|
# http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430
|
@@ -871,7 +870,13 @@ module ActiveRecord
|
|
871
870
|
end.compact.join(', ')
|
872
871
|
|
873
872
|
# ...and send them all in one query
|
874
|
-
@connection.query "SET #{encoding} #{variable_assignments}"
|
873
|
+
@connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
|
874
|
+
end
|
875
|
+
|
876
|
+
def column_definitions(table_name) # :nodoc:
|
877
|
+
execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
|
878
|
+
each_hash(result)
|
879
|
+
end
|
875
880
|
end
|
876
881
|
|
877
882
|
def extract_foreign_key_action(structure, name, action) # :nodoc:
|
@@ -891,8 +896,14 @@ module ActiveRecord
|
|
891
896
|
create_table_info_cache[table_name] ||= select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
|
892
897
|
end
|
893
898
|
|
894
|
-
def create_table_definition(
|
895
|
-
MySQL::TableDefinition.new(
|
899
|
+
def create_table_definition(*args) # :nodoc:
|
900
|
+
MySQL::TableDefinition.new(*args)
|
901
|
+
end
|
902
|
+
|
903
|
+
def extract_schema_qualified_name(string) # :nodoc:
|
904
|
+
schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
|
905
|
+
schema, name = @config[:database], schema unless name
|
906
|
+
[schema, name]
|
896
907
|
end
|
897
908
|
|
898
909
|
def integer_to_sql(limit) # :nodoc:
|
@@ -937,8 +948,8 @@ module ActiveRecord
|
|
937
948
|
class MysqlString < Type::String # :nodoc:
|
938
949
|
def serialize(value)
|
939
950
|
case value
|
940
|
-
when true then
|
941
|
-
when false then
|
951
|
+
when true then MySQL::Quoting::QUOTED_TRUE
|
952
|
+
when false then MySQL::Quoting::QUOTED_FALSE
|
942
953
|
else super
|
943
954
|
end
|
944
955
|
end
|
@@ -947,8 +958,8 @@ module ActiveRecord
|
|
947
958
|
|
948
959
|
def cast_value(value)
|
949
960
|
case value
|
950
|
-
when true then
|
951
|
-
when false then
|
961
|
+
when true then MySQL::Quoting::QUOTED_TRUE
|
962
|
+
when false then MySQL::Quoting::QUOTED_FALSE
|
952
963
|
else super
|
953
964
|
end
|
954
965
|
end
|