aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb82
1 files changed, 73 insertions, 9 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 7ca0fcfbcb..83eb5e3ef1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -6,6 +6,13 @@ module ActiveRecord
class AbstractMysqlAdapter < AbstractAdapter
include Savepoints
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
+ def primary_key(name, type = :primary_key, options = {})
+ options[:auto_increment] ||= type == :bigint
+ super
+ end
+ end
+
class SchemaCreation < AbstractAdapter::SchemaCreation
def visit_AddColumn(o)
add_column_position!(super, column_options(o))
@@ -58,6 +65,18 @@ module ActiveRecord
SchemaCreation.new self
end
+ def column_spec_for_primary_key(column)
+ spec = {}
+ if column.extra == 'auto_increment'
+ return unless column.limit == 8
+ spec[:id] = ':bigint'
+ else
+ spec[:id] = column.type.inspect
+ spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type, :null].include?(key) })
+ end
+ spec
+ end
+
class Column < ConnectionAdapters::Column # :nodoc:
attr_reader :collation, :strict, :extra
@@ -398,7 +417,7 @@ module ActiveRecord
sql << "LIKE #{quote(like)}" if like
execute_and_free(sql, 'SCHEMA') do |result|
- result.collect { |field| field.first }
+ result.collect(&:first)
end
end
@@ -487,11 +506,13 @@ module ActiveRecord
end
def drop_table(table_name, options = {})
- execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
+ execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
def rename_index(table_name, old_name, new_name)
if supports_rename_index?
+ validate_index_length!(table_name, new_name)
+
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
else
super
@@ -582,6 +603,13 @@ module ActiveRecord
when 0x1000000..0xffffffff; 'longtext'
else raise(ActiveRecordError, "No text type has character length #{limit}")
end
+ when 'datetime'
+ return super unless precision
+
+ case precision
+ when 0..6; "datetime(#{precision})"
+ else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
+ end
else
super
end
@@ -656,19 +684,25 @@ module ActiveRecord
m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
- m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
- m.register_type %r(^int)i, Type::Integer.new(limit: 4)
- m.register_type %r(^mediumint)i, Type::Integer.new(limit: 3)
- m.register_type %r(^smallint)i, Type::Integer.new(limit: 2)
- m.register_type %r(^tinyint)i, Type::Integer.new(limit: 1)
m.register_type %r(^float)i, Type::Float.new(limit: 24)
m.register_type %r(^double)i, Type::Float.new(limit: 53)
+ register_integer_type m, %r(^bigint)i, limit: 8
+ register_integer_type m, %r(^int)i, limit: 4
+ register_integer_type m, %r(^mediumint)i, limit: 3
+ register_integer_type m, %r(^smallint)i, limit: 2
+ register_integer_type m, %r(^tinyint)i, limit: 1
+
m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
m.alias_type %r(set)i, 'varchar'
m.alias_type %r(year)i, 'integer'
m.alias_type %r(bit)i, 'binary'
+ m.register_type(%r(datetime)i) do |sql_type|
+ precision = extract_precision(sql_type)
+ MysqlDateTime.new(precision: precision)
+ end
+
m.register_type(%r(enum)i) do |sql_type|
limit = sql_type[/^enum\((.+)\)/i, 1]
.split(',').map{|enum| enum.strip.length - 2}.max
@@ -676,6 +710,16 @@ module ActiveRecord
end
end
+ def register_integer_type(mapping, key, options) # :nodoc:
+ mapping.register_type(key) do |sql_type|
+ if /unsigned/i =~ sql_type
+ Type::UnsignedInteger.new(options)
+ else
+ Type::Integer.new(options)
+ end
+ end
+ end
+
# MySQL is too stupid to create a temporary table for use subquery, so we have
# to give it some prompting in the form of a subsubquery. Ugh!
def subquery_for(key, select)
@@ -779,14 +823,14 @@ module ActiveRecord
[add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
end
- def remove_timestamps_sql(table_name)
+ def remove_timestamps_sql(table_name, options = {})
[remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
end
private
def version
- @version ||= full_version.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
+ @version ||= full_version.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map(&:to_i)
end
def mariadb?
@@ -848,6 +892,26 @@ module ActiveRecord
end
end
+ def create_table_definition(name, temporary, options, as = nil) # :nodoc:
+ TableDefinition.new(native_database_types, name, temporary, options, as)
+ end
+
+ class MysqlDateTime < Type::DateTime # :nodoc:
+ def type_cast_for_database(value)
+ if value.acts_like?(:time) && value.respond_to?(:usec)
+ result = super.to_s(:db)
+ case precision
+ when 1..6
+ "#{result}.#{sprintf("%0#{precision}d", value.usec / 10 ** (6 - precision))}"
+ else
+ result
+ end
+ else
+ super
+ end
+ end
+ end
+
class MysqlString < Type::String # :nodoc:
def type_cast_for_database(value)
case value