public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
validates_uniqueness_of uses database case sensitivity support instead of using 
ruby

Signed-off-by: Michael Koziarski <michael@koziarski.com>
Tarmo Tänav (author)
Thu Jul 31 12:18:14 -0700 2008
NZKoz (committer)
Thu Jul 31 12:33:11 -0700 2008
commit  f7eaab96d332528253d14581f747dd4b1b378a06
tree    4b4b55a06722611bfcc939dca8944f8982562297
parent  f3da46effae9f23f6ea473f7296e9c0c9bb49fce
...
149
150
151
 
 
 
 
152
153
154
...
149
150
151
152
153
154
155
156
157
158
0
@@ -149,6 +149,10 @@ module ActiveRecord
0
         "INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
0
       end
0
 
0
+      def case_sensitive_equality_operator
0
+        "="
0
+      end
0
+
0
       protected
0
         # Returns an array of record hashes with the column names as keys and
0
         # column values as values.
...
511
512
513
 
 
 
 
514
515
516
...
511
512
513
514
515
516
517
518
519
520
0
@@ -511,6 +511,10 @@ module ActiveRecord
0
         keys.length == 1 ? [keys.first, nil] : nil
0
       end
0
 
0
+      def case_sensitive_equality_operator
0
+        "= BINARY"
0
+      end
0
+
0
       private
0
         def connect
0
           @connection.reconnect = true if @connection.respond_to?(:reconnect=)
...
627
628
629
630
631
 
 
 
 
 
 
 
 
632
633
 
 
634
635
 
636
637
638
639
640
 
641
642
643
...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
 
 
677
678
 
679
680
681
...
627
628
629
 
 
630
631
632
633
634
635
636
637
638
639
640
641
642
 
643
644
645
 
 
 
646
647
648
649
...
660
661
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
664
665
 
666
667
668
669
0
@@ -627,17 +627,23 @@ module ActiveRecord
0
 
0
           is_text_column = finder_class.columns_hash[attr_name.to_s].text?
0
 
0
-          if !value.nil? && is_text_column
0
-            value = value.to_s
0
+          if value.nil?
0
+            comparison_operator = "IS ?"
0
+          else
0
+            comparison_operator = "#{connection.case_sensitive_equality_operator} ?"
0
+
0
+            if is_text_column
0
+              value = value.to_s
0
+            end
0
           end
0
 
0
+          sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
0
+
0
           if value.nil? || (configuration[:case_sensitive] || !is_text_column)
0
-            condition_sql = "#{record.class.quoted_table_name}.#{attr_name} #{attribute_condition(value)}"
0
+            condition_sql = "#{sql_attribute} #{comparison_operator}"
0
             condition_params = [value]
0
           else
0
-            # sqlite has case sensitive SELECT query, while MySQL/Postgresql don't.
0
-            # Hence, this is needed only for sqlite.
0
-            condition_sql = "LOWER(#{record.class.quoted_table_name}.#{attr_name}) #{attribute_condition(value)}"
0
+            condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
0
             condition_params = [value.downcase]
0
           end
0
 
0
@@ -654,28 +660,10 @@ module ActiveRecord
0
             condition_params << record.send(:id)
0
           end
0
 
0
-          results = finder_class.with_exclusive_scope do
0
-            connection.select_all(
0
-              construct_finder_sql(
0
-                :select     => "#{connection.quote_column_name(attr_name)}",
0
-                :from       => "#{finder_class.quoted_table_name}",
0
-                :conditions => [condition_sql, *condition_params]
0
-              )
0
-            )
0
-          end
0
-
0
-          unless results.length.zero?
0
-            found = true
0
-
0
-            # As MySQL/Postgres don't have case sensitive SELECT queries, we try to find duplicate
0
-            # column in ruby when case sensitive option
0
-            if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text?
0
-              found = results.any? { |a| a[attr_name.to_s] == value.to_s }
0
-            end
0
-            
0
-            if found
0
+          finder_class.with_exclusive_scope do
0
+            if finder_class.exists?([condition_sql, *condition_params])
0
               message = record.errors.generate_message(attr_name, :taken, :default => configuration[:message])
0
-              record.errors.add(attr_name, message) 
0
+              record.errors.add(attr_name, message)
0
             end
0
           end
0
         end

Comments

trevorturk Thu Jul 31 14:26:47 -0700 2008

Sweet!