提交 446f2521 编写于 作者: R Ryuta Kamizono

Move the collation handling code from the MySQL adapter to common classes

Some databases like MySQL allow defining collation charset for specific
columns.
上级 8ce44b28
......@@ -70,6 +70,7 @@ def column_options(o)
column_options[:after] = o.after
column_options[:auto_increment] = o.auto_increment
column_options[:primary_key] = o.primary_key
column_options[:collation] = o.collation
column_options
end
......
......@@ -15,7 +15,7 @@ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :
# are typically created by methods in TableDefinition, and added to the
# +columns+ attribute of said TableDefinition object, in order to be used
# for generating a number of table creation or table changing SQL statements.
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :sql_type) #:nodoc:
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type) #:nodoc:
def primary_key?
primary_key || type.to_sym == :primary_key
......@@ -434,6 +434,7 @@ def new_column_definition(name, type, options) # :nodoc:
column.after = options[:after]
column.auto_increment = options[:auto_increment]
column.primary_key = type == :primary_key || options[:primary_key]
column.collation = options[:collation]
column
end
......
......@@ -35,12 +35,16 @@ def prepare_column_options(column)
default = schema_default(column) if column.has_default?
spec[:default] = default unless default.nil?
if collation = schema_collation(column)
spec[:collation] = collation
end
spec
end
# Lists the valid migration options
def migration_keys
[:name, :limit, :precision, :scale, :default, :null]
[:name, :limit, :precision, :scale, :default, :null, :collation]
end
private
......@@ -56,6 +60,10 @@ def schema_default(column)
type.type_cast_for_schema(default)
end
end
def schema_collation(column)
column.collation.inspect if column.collation
end
end
end
end
......@@ -387,8 +387,8 @@ def type_map # :nodoc:
end
end
def new_column(name, default, sql_type_metadata = nil, null = true)
Column.new(name, default, sql_type_metadata, null)
def new_column(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil)
Column.new(name, default, sql_type_metadata, null, default_function, collation)
end
def lookup_cast_type(sql_type) # :nodoc:
......
......@@ -14,7 +14,7 @@ def primary_key(name, type = :primary_key, **options)
end
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
attr_accessor :charset, :collation
attr_accessor :charset
end
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
......@@ -28,7 +28,6 @@ def new_column_definition(name, type, options) # :nodoc:
column.auto_increment = true
end
column.charset = options[:charset]
column.collation = options[:collation]
column
end
......@@ -75,7 +74,6 @@ def visit_ChangeColumnDefinition(o)
def column_options(o)
column_options = super
column_options[:charset] = o.charset
column_options[:collation] = o.collation
column_options
end
......@@ -128,20 +126,20 @@ def prepare_column_options(column)
spec = super
spec.delete(:precision) if /time/ === column.sql_type && column.precision == 0
spec.delete(:limit) if :boolean === column.type
spec
end
def schema_collation(column)
if column.collation && table_name = column.instance_variable_get(:@table_name)
@collation_cache ||= {}
@collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
spec[:collation] = column.collation.inspect if column.collation != @collation_cache[table_name]
column.collation.inspect if column.collation != @collation_cache[table_name]
end
spec
end
def migration_keys
super + [:collation]
end
private :schema_collation
class Column < ConnectionAdapters::Column # :nodoc:
delegate :strict, :collation, :extra, to: :sql_type_metadata, allow_nil: true
delegate :strict, :extra, to: :sql_type_metadata, allow_nil: true
def initialize(*)
super
......@@ -195,12 +193,11 @@ def assert_valid_default(default)
end
class MysqlTypeMetadata < DelegateClass(SqlTypeMetadata) # :nodoc:
attr_reader :collation, :extra, :strict
attr_reader :extra, :strict
def initialize(type_metadata, collation: "", extra: "", strict: false)
def initialize(type_metadata, extra: "", strict: false)
super(type_metadata)
@type_metadata = type_metadata
@collation = collation
@extra = extra
@strict = strict
end
......@@ -218,7 +215,7 @@ def hash
protected
def attributes_for_hash
[self.class, @type_metadata, collation, extra, strict]
[self.class, @type_metadata, extra, strict]
end
end
......@@ -342,8 +339,8 @@ def each_hash(result) # :nodoc:
raise NotImplementedError
end
def new_column(field, default, sql_type_metadata = nil, null = true) # :nodoc:
Column.new(field, default, sql_type_metadata, null)
def new_column(field, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil) # :nodoc:
Column.new(field, default, sql_type_metadata, null, default_function, collation)
end
# Must return the MySQL error number from the exception, if the exception has an
......@@ -566,8 +563,8 @@ def columns(table_name)#:nodoc:
each_hash(result).map do |field|
field_name = set_field_encoding(field[:Field])
sql_type = field[:Type]
type_metadata = fetch_type_metadata(sql_type, field[:Collation], field[:Extra])
new_column(field_name, field[:Default], type_metadata, field[:Null] == "YES")
type_metadata = fetch_type_metadata(sql_type, field[:Extra])
new_column(field_name, field[:Default], type_metadata, field[:Null] == "YES", nil, field[:Collation])
end
end
end
......@@ -826,8 +823,8 @@ def extract_precision(sql_type)
end
end
def fetch_type_metadata(sql_type, collation = "", extra = "")
MysqlTypeMetadata.new(super(sql_type), collation: collation, extra: extra, strict: strict_mode?)
def fetch_type_metadata(sql_type, extra = "")
MysqlTypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?)
end
# MySQL is too stupid to create a temporary table for use subquery, so we have
......
......@@ -12,7 +12,7 @@ module Format
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
end
attr_reader :name, :null, :sql_type_metadata, :default, :default_function
attr_reader :name, :null, :sql_type_metadata, :default, :default_function, :collation
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
......@@ -22,12 +22,13 @@ module Format
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
# +sql_type_metadata+ is various information about the type of the column
# +null+ determines if this column allows +NULL+ values.
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil)
def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil)
@name = name
@sql_type_metadata = sql_type_metadata
@null = null
@default = default
@default_function = default_function
@collation = collation
@table_name = nil
end
......@@ -60,7 +61,7 @@ def hash
protected
def attributes_for_hash
[self.class, name, default, sql_type_metadata, null, default_function]
[self.class, name, default, sql_type_metadata, null, default_function, collation]
end
end
......
......@@ -169,8 +169,8 @@ def columns(table_name)
end
end
def new_column(name, default, sql_type_metadata = nil, null = true, default_function = nil) # :nodoc:
PostgreSQLColumn.new(name, default, sql_type_metadata, null, default_function)
def new_column(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil) # :nodoc:
PostgreSQLColumn.new(name, default, sql_type_metadata, null, default_function, collation)
end
# Returns the current database name.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册