Title: [628] trunk/activerecord-jdbc: Fix bug when quoting on Derby or MySQL with shared strings.
Revision
628
Author
olabini
Date
2007-06-14 09:52:16 -0400 (Thu, 14 Jun 2007)

Log Message

Fix bug when quoting on Derby or MySQL with shared strings. Also adds more performance Derby quoting

Modified Paths

Diff

Modified: trunk/activerecord-jdbc/lib/jdbc_adapter/jdbc_derby.rb (627 => 628)


--- trunk/activerecord-jdbc/lib/jdbc_adapter/jdbc_derby.rb	2007-06-14 12:48:21 UTC (rev 627)
+++ trunk/activerecord-jdbc/lib/jdbc_adapter/jdbc_derby.rb	2007-06-14 13:52:16 UTC (rev 628)
@@ -373,44 +373,6 @@
       end
     end
     
-    def quote(value, column = nil) # :nodoc:
-      return value.to_s if column && column.type == :primary_key
-
-      case value
-      when String
-        if column 
-          case column.type
-          when :binary
-            "CAST(x'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}' AS BLOB)"
-          when :text
-            "CAST('#{quote_string(value)}' AS CLOB)"
-          when :string
-            "'#{quote_string(value)}'"
-          else
-            if value =~ /^\d+$/
-              value
-            else
-              super
-            end
-          end
-        else
-          super
-        end
-      when Float, Fixnum, Bignum
-          if column
-            case column.type
-            when :string
-              "'#{quote_string(value.to_s)}'"
-            else
-              super
-            end
-          else
-            super
-          end
-      else super
-      end
-    end
-
     def native_database_types #:nodoc:
       {
         :primary_key=>"int generated by default as identity NOT NULL PRIMARY KEY", 

Modified: trunk/activerecord-jdbc/src/java/JDBCDerbySpec.java (627 => 628)


--- trunk/activerecord-jdbc/src/java/JDBCDerbySpec.java	2007-06-14 12:48:21 UTC (rev 627)
+++ trunk/activerecord-jdbc/src/java/JDBCDerbySpec.java	2007-06-14 13:52:16 UTC (rev 628)
@@ -29,7 +29,13 @@
 import org.jruby.Ruby;
 import org.jruby.RubyModule;
 import org.jruby.RubyString;
+import org.jruby.RubyFloat;
+import org.jruby.RubyFixnum;
+import org.jruby.RubyBignum;
+import org.jruby.RubyBoolean;
+import org.jruby.RubyBigDecimal;
 
+import org.jruby.runtime.Arity;
 import org.jruby.runtime.CallbackFactory;
 import org.jruby.runtime.ThreadContext;
 import org.jruby.runtime.builtin.IRubyObject;
@@ -41,10 +47,131 @@
         RubyModule derby = jdbcSpec.defineModuleUnder("Derby");
         CallbackFactory cf = runtime.callbackFactory(JDBCDerbySpec.class);
         derby.defineFastMethod("quote_string",cf.getFastSingletonMethod("quote_string",IRubyObject.class));
+        derby.defineFastMethod("quote",cf.getFastOptSingletonMethod("quote"));
     }
 
+    public static IRubyObject quote(IRubyObject recv, IRubyObject[] args) {
+        Ruby runtime = recv.getRuntime();
+        Arity.checkArgumentCount(runtime, args, 1, 2);
+        IRubyObject value = args[0];
+        if(args.length > 1) {
+            IRubyObject col = args[1];
+            if(value instanceof RubyString) {
+                    IRubyObject type = col.callMethod(runtime.getCurrentContext(),"type");
+                    if(type == runtime.newSymbol("string")) {
+                        return quote_string_with_surround(runtime, "'", (RubyString)value, "'");
+                    } else if(type == runtime.newSymbol("text")) {
+                        return quote_string_with_surround(runtime, "CAST('", (RubyString)value, "' AS CLOB)");
+                    } else if(type == runtime.newSymbol("binary")) {
+                        return hexquote_string_with_surround(runtime, "CAST('", (RubyString)value, "' AS BLOB)");
+                    } else {
+                        // column type :integer or other numeric or date version
+                        if(only_digits((RubyString)value)) {
+                            return value;
+                        } else {
+                            return super_quote(recv, runtime, value, col);
+                        }
+                    }
+            } else if((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
+                if(col == runtime.newSymbol("string")) {
+                    return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'");
+                }
+            }
+        } 
+        return super_quote(recv, runtime, value, runtime.getNil());
+    }
+
+    private final static ByteList NULL = new ByteList("NULL".getBytes());
+
+    public static IRubyObject super_quote(IRubyObject recv, Ruby runtime, IRubyObject value, IRubyObject col) {
+        if(value.respondsTo("quoted_id")) {
+            return value.callMethod(runtime.getCurrentContext(), "quoted_id");
+        }
+        
+        IRubyObject type = (col.isNil()) ? col : col.callMethod(runtime.getCurrentContext(),"type");
+        if(value instanceof RubyString || 
+           value.isKindOf(runtime.getClassFromPath("ActiveSupport::Multibyte::Chars"))) {
+            RubyString svalue = RubyString.objAsString(value);
+            if(type == runtime.newSymbol("binary") && col.getType().respondsTo("string_to_binary")) {
+                return quote_string_with_surround(runtime, "'", (RubyString)(col.getType().callMethod(runtime.getCurrentContext(), "string_to_binary", svalue)), "'"); 
+            } else if(type == runtime.newSymbol("integer") || type == runtime.newSymbol("float")) {
+                return RubyString.objAsString(((type == runtime.newSymbol("integer")) ? 
+                                               svalue.callMethod(runtime.getCurrentContext(), "to_i") : 
+                                               svalue.callMethod(runtime.getCurrentContext(), "to_f")));
+            } else {
+                return quote_string_with_surround(runtime, "'", svalue, "'"); 
+            }
+        } else if(value.isNil()) {
+            return runtime.newStringShared(NULL);
+        } else if(value instanceof RubyBoolean) {
+            return (value.isTrue() ? 
+                    (type == runtime.newSymbol(":integer")) ? runtime.newString("1") : recv.callMethod(runtime.getCurrentContext(),"quoted_true") :
+                    (type == runtime.newSymbol(":integer")) ? runtime.newString("0") : recv.callMethod(runtime.getCurrentContext(),"quoted_false"));
+        } else if((value instanceof RubyFloat) || (value instanceof RubyFixnum) || (value instanceof RubyBignum)) {
+            return RubyString.objAsString(value);
+        } else if(value instanceof RubyBigDecimal) {
+            return value.callMethod(runtime.getCurrentContext(), "to_s", runtime.newString("F"));
+        } else if(value.isKindOf(runtime.getModule("Date"))) {
+            return quote_string_with_surround(runtime, "'", RubyString.objAsString(value), "'"); 
+        } else if(value.isKindOf(runtime.getModule("Time")) || value.isKindOf(runtime.getModule("DateTime"))) {
+            return quote_string_with_surround(runtime, "'", (RubyString)(recv.callMethod(runtime.getCurrentContext(), "quoted_date", value)), "'"); 
+        } else {
+            return quote_string_with_surround(runtime, "'", (RubyString)(value.callMethod(runtime.getCurrentContext(), "to_yaml")), "'");
+        }
+    }
+
     private final static ByteList TWO_SINGLE = new ByteList(new byte[]{'\'','\''});
 
+    public static IRubyObject quote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
+        ByteList input = string.getByteList();
+        ByteList output = new ByteList(before.getBytes());
+        for(int i = input.begin; i< input.begin + input.realSize; i++) {
+            switch(input.bytes[i]) {
+            case '\'':
+                output.append(input.bytes[i]);
+                //FALLTHROUGH
+            default:
+                output.append(input.bytes[i]);
+            }
+
+        }
+
+        output.append(after.getBytes());
+
+        return runtime.newStringShared(output);
+    }
+
+    private final static byte[] HEX = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+    public static IRubyObject hexquote_string_with_surround(Ruby runtime, String before, RubyString string, String after) {
+        ByteList input = string.getByteList();
+        ByteList output = new ByteList(before.getBytes());
+        for(int i = input.begin; i< input.begin + input.realSize; i++) {
+            byte b1 = input.bytes[i];
+            byte higher = HEX[(((char)b1)>>4)%16];
+            byte lower = HEX[((char)b1)%16];
+            if(b1 == '\'') {
+                output.append(higher);
+                output.append(lower);
+            }
+            output.append(higher);
+            output.append(lower);
+        }
+
+        output.append(after.getBytes());
+        return runtime.newStringShared(output);
+    }
+
+    private static boolean only_digits(RubyString inp) {
+        ByteList input = inp.getByteList();
+        for(int i = input.begin; i< input.begin + input.realSize; i++) {
+            if(input.bytes[i] < '0' || input.bytes[i] > '9') {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public static IRubyObject quote_string(IRubyObject recv, IRubyObject string) {
         boolean replacementFound = false;
         ByteList bl = ((RubyString) string).getByteList();
@@ -57,6 +184,7 @@
             
             // On first replacement allocate a different bytelist so we don't manip original 
             if(!replacementFound) {
+                i-= bl.begin;
                 bl = new ByteList(bl);
                 replacementFound = true;
             }

Modified: trunk/activerecord-jdbc/src/java/JDBCMySQLSpec.java (627 => 628)


--- trunk/activerecord-jdbc/src/java/JDBCMySQLSpec.java	2007-06-14 12:48:21 UTC (rev 627)
+++ trunk/activerecord-jdbc/src/java/JDBCMySQLSpec.java	2007-06-14 13:52:16 UTC (rev 628)
@@ -70,6 +70,7 @@
             
             // On first replacement allocate a different bytelist so we don't manip original 
             if(!replacementFound) {
+                i-= bl.begin;
                 bl = new ByteList(bl);
                 replacementFound = true;
             }
_______________________________________________
Jruby-extras-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/jruby-extras-devel

Reply via email to