--- oracle_adapter.rb.orig	2007-05-23 20:25:49.000000000 -0400
+++ oracle_adapter.rb	2007-05-23 22:12:34.000000000 -0400
@@ -4,6 +4,8 @@
 #
 # Current maintainer: Michael Schoen <schoenm@earthlink.net>
 #
+# With bind variable hacks by Robert Thau, rst@alum.mit.edu
+#
 #########################################################################
 #
 # Implementation notes:
@@ -165,26 +167,90 @@
           name =~ /[A-Z]/ ? "\"#{name}\"" : name
         end
 
+        START_BREADCRUMB  = "\001"
+        STRING_BREADCRUMB = "\002"
+        NUMBER_BREADCRUMB = "\003"
+
+        def quote_typed_val( breadcrumb, val )
+          str = val.to_s
+          START_BREADCRUMB + breadcrumb + str.size.to_s + '.' + str
+        end
+
         def quote_string(s) #:nodoc:
-          s.gsub(/'/, "''")
+          quote_typed_val(STRING_BREADCRUMB, s)
+        end
+
+        def quote_number(n)
+          quote_typed_val(NUMBER_BREADCRUMB, n)
         end
 
         def quote(value, column = nil) #:nodoc:
+
           if column && [:text, :binary].include?(column.type)
-            %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
-          else
-            super
+            return %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
+          end
+
+          # ActiveRecord::Base#quoted_id invokes this 'quote' recursively
+
+          return value.quoted_id if value.respond_to?(:quoted_id)
+
+          case value
+          when String, ActiveSupport::Multibyte::Chars
+            value = value.to_s
+            if column && column.type == :binary && 
+                         column.class.respond_to?(:string_to_binary)
+              quote_string(column.class.string_to_binary(value))
+            elsif column && [:integer, :float].include?(column.type)
+              value = column.type == :integer ? value.to_i : value.to_f
+              quote_number(value)
+            else
+              quote_string(value)
+            end
+          when NilClass   then "NULL"
+          when TrueClass  then quote_number(1)
+          when FalseClass then quote_number(0)
+          when Float, Fixnum, Bignum    
+                          then quote_number(value)
+          # BigDecimals need to be output in a non-normalized form and quoted.
+          when BigDecimal then quote_number(value.to_s('F'))
+          when Date       then "'#{value.to_s}'"
+          when Time, DateTime           
+                          then "'#{quoted_date(value)}'"
+          else                 quote_string(value.to_yaml)
           end
         end
 
         def quoted_true
-          "1"
+          quote_number(1)
         end
 
         def quoted_false
-          "0"
+          quote_number(0)
         end
 
+        def untangle_quotes(sql)
+          sql = sql.dup
+          bindvars = []
+          while (next_bind_pos = sql.index(START_BREADCRUMB))
+
+            type_breadcrumb = sql[next_bind_pos + 1]
+            len_end_pos     = sql.index('.', next_bind_pos + 2)
+            len             = sql[(next_bind_pos + 2)..(len_end_pos - 1)].to_i
+            val_start_pos   = len_end_pos + 1
+            val_end_pos     = val_start_pos + len - 1
+
+            value                           = sql[val_start_pos..val_end_pos]
+            sql[next_bind_pos..val_end_pos] = ':v' + bindvars.size.to_s
+
+            case type_breadcrumb
+            when STRING_BREADCRUMB[0] then bindvars << value
+            when NUMBER_BREADCRUMB[0] then bindvars << value 
+            else raise ArgumentError, "Unexpected breadcrumb " + type_breadcrumb.inspect
+            end
+
+          end
+          return sql, bindvars
+        end
 
         # CONNECTION MANAGEMENT ====================================
         #
@@ -219,7 +285,10 @@
         # see: abstract/database_statements.rb
 
         def execute(sql, name = nil) #:nodoc:
-          log(sql, name) { @connection.exec sql }
+          real_sql, bindvars = untangle_quotes sql
+          log(real_sql + " % " + bindvars.inspect, name) { 
+            @connection.exec real_sql, *bindvars
+          }
         end
 
         # Returns the next sequence value from a sequence generator. Not generally
