1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Only use BINARY for mysql case sensitive uniqueness check when column has a case insensitive collation.

This commit is contained in:
Ryuta Kamizono 2013-11-26 04:59:18 +09:00
parent a6900a2073
commit 501ae92a32
6 changed files with 62 additions and 6 deletions

View file

@ -1,3 +1,7 @@
* Only use BINARY for mysql case sensitive uniqueness check when column has a case insensitive collation.
*Ryuta Kamizono*
* Fix validation on uniqueness of empty association. * Fix validation on uniqueness of empty association.
*Evgeny Li* *Evgeny Li*

View file

@ -334,6 +334,11 @@ module ActiveRecord
node node
end end
def case_sensitive_comparison(table, attribute, column, value)
value = case_sensitive_modifier(value) unless value.nil?
table[attribute].eq(value)
end
def case_insensitive_comparison(table, attribute, column, value) def case_insensitive_comparison(table, attribute, column, value)
table[attribute].lower.eq(table.lower(value)) table[attribute].lower.eq(table.lower(value))
end end

View file

@ -585,6 +585,14 @@ module ActiveRecord
Arel::Nodes::Bin.new(node) Arel::Nodes::Bin.new(node)
end end
def case_sensitive_comparison(table, attribute, column, value)
if column.case_sensitive?
table[attribute].eq(value)
else
super
end
end
def case_insensitive_comparison(table, attribute, column, value) def case_insensitive_comparison(table, attribute, column, value)
if column.case_sensitive? if column.case_sensitive?
super super

View file

@ -59,8 +59,7 @@ module ActiveRecord
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
klass.connection.case_insensitive_comparison(table, attribute, column, value) klass.connection.case_insensitive_comparison(table, attribute, column, value)
else else
value = klass.connection.case_sensitive_modifier(value) unless value.nil? klass.connection.case_sensitive_comparison(table, attribute, column, value)
table[attribute].eq(value)
end end
end end

View file

@ -3,10 +3,10 @@ require 'models/person'
class MysqlCaseSensitivityTest < ActiveRecord::TestCase class MysqlCaseSensitivityTest < ActiveRecord::TestCase
class CollationTest < ActiveRecord::Base class CollationTest < ActiveRecord::Base
validates_uniqueness_of :string_cs_column, :case_sensitive => false
validates_uniqueness_of :string_ci_column, :case_sensitive => false
end end
repair_validations(CollationTest)
def test_columns_include_collation_different_from_table def test_columns_include_collation_different_from_table
assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation
assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation
@ -18,6 +18,7 @@ class MysqlCaseSensitivityTest < ActiveRecord::TestCase
end end
def test_case_insensitive_comparison_for_ci_column def test_case_insensitive_comparison_for_ci_column
CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => false)
CollationTest.create!(:string_ci_column => 'A') CollationTest.create!(:string_ci_column => 'A')
invalid = CollationTest.new(:string_ci_column => 'a') invalid = CollationTest.new(:string_ci_column => 'a')
queries = assert_sql { invalid.save } queries = assert_sql { invalid.save }
@ -26,10 +27,29 @@ class MysqlCaseSensitivityTest < ActiveRecord::TestCase
end end
def test_case_insensitive_comparison_for_cs_column def test_case_insensitive_comparison_for_cs_column
CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => false)
CollationTest.create!(:string_cs_column => 'A') CollationTest.create!(:string_cs_column => 'A')
invalid = CollationTest.new(:string_cs_column => 'a') invalid = CollationTest.new(:string_cs_column => 'a')
queries = assert_sql { invalid.save } queries = assert_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_match(/lower/i, cs_uniqueness_query) assert_match(/lower/i, cs_uniqueness_query)
end end
def test_case_sensitive_comparison_for_ci_column
CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => true)
CollationTest.create!(:string_ci_column => 'A')
invalid = CollationTest.new(:string_ci_column => 'A')
queries = assert_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_match(/binary/i, ci_uniqueness_query)
end
def test_case_sensitive_comparison_for_cs_column
CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => true)
CollationTest.create!(:string_cs_column => 'A')
invalid = CollationTest.new(:string_cs_column => 'A')
queries = assert_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_no_match(/binary/i, cs_uniqueness_query)
end
end end

View file

@ -3,10 +3,10 @@ require 'models/person'
class Mysql2CaseSensitivityTest < ActiveRecord::TestCase class Mysql2CaseSensitivityTest < ActiveRecord::TestCase
class CollationTest < ActiveRecord::Base class CollationTest < ActiveRecord::Base
validates_uniqueness_of :string_cs_column, :case_sensitive => false
validates_uniqueness_of :string_ci_column, :case_sensitive => false
end end
repair_validations(CollationTest)
def test_columns_include_collation_different_from_table def test_columns_include_collation_different_from_table
assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation
assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation
@ -18,6 +18,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::TestCase
end end
def test_case_insensitive_comparison_for_ci_column def test_case_insensitive_comparison_for_ci_column
CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => false)
CollationTest.create!(:string_ci_column => 'A') CollationTest.create!(:string_ci_column => 'A')
invalid = CollationTest.new(:string_ci_column => 'a') invalid = CollationTest.new(:string_ci_column => 'a')
queries = assert_sql { invalid.save } queries = assert_sql { invalid.save }
@ -26,10 +27,29 @@ class Mysql2CaseSensitivityTest < ActiveRecord::TestCase
end end
def test_case_insensitive_comparison_for_cs_column def test_case_insensitive_comparison_for_cs_column
CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => false)
CollationTest.create!(:string_cs_column => 'A') CollationTest.create!(:string_cs_column => 'A')
invalid = CollationTest.new(:string_cs_column => 'a') invalid = CollationTest.new(:string_cs_column => 'a')
queries = assert_sql { invalid.save } queries = assert_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)} cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)}
assert_match(/lower/i, cs_uniqueness_query) assert_match(/lower/i, cs_uniqueness_query)
end end
def test_case_sensitive_comparison_for_ci_column
CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => true)
CollationTest.create!(:string_ci_column => 'A')
invalid = CollationTest.new(:string_ci_column => 'A')
queries = assert_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_match(/binary/i, ci_uniqueness_query)
end
def test_case_sensitive_comparison_for_cs_column
CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => true)
CollationTest.create!(:string_cs_column => 'A')
invalid = CollationTest.new(:string_cs_column => 'A')
queries = assert_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_no_match(/binary/i, cs_uniqueness_query)
end
end end