提交 0aa83f3b 编写于 作者: R Ryuta Kamizono

Add `:charset` and `:collation` options support for MySQL string and text columns

Example:

    create_table :foos do |t|
      t.string :string_utf8_bin, charset: 'utf8', collation: 'utf8_bin'
      t.text   :text_ascii,      charset: 'ascii'
    end
上级 eac33492
* Add `:charset` and `:collation` options support for MySQL string and text columns.
Example:
create_table :foos do |t|
t.string :string_utf8_bin, charset: 'utf8', collation: 'utf8_bin'
t.text :text_ascii, charset: 'ascii'
end
*Ryuta Kamizono*
* Correctly dump `serial` and `bigserial`.
*Ryuta Kamizono*
......
......@@ -13,6 +13,10 @@ def primary_key(name, type = :primary_key, **options)
end
end
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
attr_accessor :charset, :collation
end
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
include ColumnMethods
......@@ -23,8 +27,16 @@ def new_column_definition(name, type, options) # :nodoc:
column.type = :integer
column.auto_increment = true
end
column.charset = options[:charset]
column.collation = options[:collation]
column
end
private
def create_column_definition(name, type)
ColumnDefinition.new(name, type)
end
end
class Table < ActiveRecord::ConnectionAdapters::Table
......@@ -60,6 +72,23 @@ def visit_ChangeColumnDefinition(o)
add_column_position!(change_column_sql, column_options(o.column))
end
def column_options(o)
column_options = super
column_options[:charset] = o.charset
column_options[:collation] = o.collation
column_options
end
def add_column_options!(sql, options)
if options[:charset]
sql << " CHARACTER SET #{options[:charset]}"
end
if options[:collation]
sql << " COLLATE #{options[:collation]}"
end
super
end
def add_column_position!(sql, options)
if options[:first]
sql << " FIRST"
......@@ -99,9 +128,18 @@ 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
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]
end
spec
end
def migration_keys
super + [:collation]
end
class Column < ConnectionAdapters::Column # :nodoc:
delegate :strict, :collation, :extra, to: :sql_type_metadata, allow_nil: true
......
......@@ -28,6 +28,7 @@ def initialize(name, default, sql_type_metadata = nil, null = true, default_func
@null = null
@default = default
@default_function = default_function
@table_name = nil
end
def has_default?
......
......@@ -105,7 +105,10 @@ def tables(stream)
end
def table(table, stream)
columns = @connection.columns(table)
columns = @connection.columns(table).map do |column|
column.instance_variable_set(:@table_name, table)
column
end
begin
tbl = StringIO.new
......
require "cases/helper"
require 'support/schema_dumping_helper'
class CharsetCollationTest < ActiveRecord::TestCase
include SchemaDumpingHelper
self.use_transactional_fixtures = false
setup do
@connection = ActiveRecord::Base.connection
@connection.create_table :charset_collations, force: true do |t|
t.string :string_ascii_bin, charset: 'ascii', collation: 'ascii_bin'
t.text :text_ucs2_unicode_ci, charset: 'ucs2', collation: 'ucs2_unicode_ci'
end
end
teardown do
@connection.drop_table :charset_collations, if_exists: true
end
test "string column with charset and collation" do
column = @connection.columns(:charset_collations).find { |c| c.name == 'string_ascii_bin' }
assert_equal :string, column.type
assert_equal 'ascii_bin', column.collation
end
test "text column with charset and collation" do
column = @connection.columns(:charset_collations).find { |c| c.name == 'text_ucs2_unicode_ci' }
assert_equal :text, column.type
assert_equal 'ucs2_unicode_ci', column.collation
end
test "add column with charset and collation" do
@connection.add_column :charset_collations, :title, :string, charset: 'utf8', collation: 'utf8_bin'
column = @connection.columns(:charset_collations).find { |c| c.name == 'title' }
assert_equal :string, column.type
assert_equal 'utf8_bin', column.collation
end
test "change column with charset and collation" do
@connection.add_column :charset_collations, :description, :string, charset: 'utf8', collation: 'utf8_unicode_ci'
@connection.change_column :charset_collations, :description, :text, charset: 'utf8', collation: 'utf8_general_ci'
column = @connection.columns(:charset_collations).find { |c| c.name == 'description' }
assert_equal :text, column.type
assert_equal 'utf8_general_ci', column.collation
end
test "schema dump includes collation" do
output = dump_table_schema("charset_collations")
assert_match %r{t.string\s+"string_ascii_bin",\s+limit: 255,\s+collation: "ascii_bin"$}, output
assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output
end
end
require "cases/helper"
require 'support/schema_dumping_helper'
class CharsetCollationTest < ActiveRecord::TestCase
include SchemaDumpingHelper
self.use_transactional_fixtures = false
setup do
@connection = ActiveRecord::Base.connection
@connection.create_table :charset_collations, force: true do |t|
t.string :string_ascii_bin, charset: 'ascii', collation: 'ascii_bin'
t.text :text_ucs2_unicode_ci, charset: 'ucs2', collation: 'ucs2_unicode_ci'
end
end
teardown do
@connection.drop_table :charset_collations, if_exists: true
end
test "string column with charset and collation" do
column = @connection.columns(:charset_collations).find { |c| c.name == 'string_ascii_bin' }
assert_equal :string, column.type
assert_equal 'ascii_bin', column.collation
end
test "text column with charset and collation" do
column = @connection.columns(:charset_collations).find { |c| c.name == 'text_ucs2_unicode_ci' }
assert_equal :text, column.type
assert_equal 'ucs2_unicode_ci', column.collation
end
test "add column with charset and collation" do
@connection.add_column :charset_collations, :title, :string, charset: 'utf8', collation: 'utf8_bin'
column = @connection.columns(:charset_collations).find { |c| c.name == 'title' }
assert_equal :string, column.type
assert_equal 'utf8_bin', column.collation
end
test "change column with charset and collation" do
@connection.add_column :charset_collations, :description, :string, charset: 'utf8', collation: 'utf8_unicode_ci'
@connection.change_column :charset_collations, :description, :text, charset: 'utf8', collation: 'utf8_general_ci'
column = @connection.columns(:charset_collations).find { |c| c.name == 'description' }
assert_equal :text, column.type
assert_equal 'utf8_general_ci', column.collation
end
test "schema dump includes collation" do
output = dump_table_schema("charset_collations")
assert_match %r{t.string\s+"string_ascii_bin",\s+limit: 255,\s+collation: "ascii_bin"$}, output
assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output
end
end
......@@ -24,6 +24,11 @@
add_index :key_tests, :pizza, :using => :btree, :name => 'index_key_tests_on_pizza'
add_index :key_tests, :snacks, :name => 'index_key_tests_on_snack'
create_table :collation_tests, id: false, force: true do |t|
t.string :string_cs_column, limit: 1, collation: 'utf8_bin'
t.string :string_ci_column, limit: 1, collation: 'utf8_general_ci'
end
ActiveRecord::Base.connection.execute <<-SQL
DROP PROCEDURE IF EXISTS ten;
SQL
......@@ -33,15 +38,6 @@
BEGIN
select 10;
END
SQL
ActiveRecord::Base.connection.drop_table "collation_tests", if_exists: true
ActiveRecord::Base.connection.execute <<-SQL
CREATE TABLE collation_tests (
string_cs_column VARCHAR(1) COLLATE utf8_bin,
string_ci_column VARCHAR(1) COLLATE utf8_general_ci
) CHARACTER SET utf8 COLLATE utf8_general_ci
SQL
ActiveRecord::Base.connection.drop_table "enum_tests", if_exists: true
......
......@@ -24,6 +24,11 @@
add_index :key_tests, :pizza, :using => :btree, :name => 'index_key_tests_on_pizza'
add_index :key_tests, :snacks, :name => 'index_key_tests_on_snack'
create_table :collation_tests, id: false, force: true do |t|
t.string :string_cs_column, limit: 1, collation: 'utf8_bin'
t.string :string_ci_column, limit: 1, collation: 'utf8_general_ci'
end
ActiveRecord::Base.connection.execute <<-SQL
DROP PROCEDURE IF EXISTS ten;
SQL
......@@ -44,15 +49,6 @@
BEGIN
select * from topics limit 1;
END
SQL
ActiveRecord::Base.connection.drop_table "collation_tests", if_exists: true
ActiveRecord::Base.connection.execute <<-SQL
CREATE TABLE collation_tests (
string_cs_column VARCHAR(1) COLLATE utf8_bin,
string_ci_column VARCHAR(1) COLLATE utf8_general_ci
) CHARACTER SET utf8 COLLATE utf8_general_ci
SQL
ActiveRecord::Base.connection.drop_table "enum_tests", if_exists: true
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册