<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -211,7 +211,7 @@ public final class Connection extends DORubyObject {
 
         // Callback for setting connection properties after connection is established
         try {
-            driver.afterConnectionCallback(conn, query);
+            driver.afterConnectionCallback(this, conn, query);
         } catch (SQLException ex) {
             throw driver.newDriverError(runtime, &quot;Connection initialization error:&quot;
                                         + &quot;\n\t&quot; + ex.getLocalizedMessage());
@@ -254,6 +254,12 @@ public final class Connection extends DORubyObject {
         return getRuntime().newString(quoted);
     }
 
+    @JRubyMethod(required = 1)
+    public IRubyObject quote_byte_array(final IRubyObject value) {
+        String quoted = driver.quoteByteArray(this, value);
+        return getRuntime().newString(quoted);
+    }
+
     // -------------------------------------------------- PRIVATE HELPER METHODS
     private IRubyObject wrappedConnection(final java.sql.Connection c) {
         return Java.java_to_ruby(this, JavaObject.wrap(this.getRuntime(), c),</diff>
      <filename>do_jdbc/src/main/java/data_objects/Connection.java</filename>
    </modified>
    <modified>
      <diff>@@ -448,7 +448,8 @@ public abstract class AbstractDriverDefinition implements DriverDefinition {
         return new Properties();
     }
 
-    public void afterConnectionCallback(Connection connection, Map&lt;String, String&gt; query) throws SQLException {
+    public void afterConnectionCallback(IRubyObject doConn, Connection conn,
+            Map&lt;String, String&gt; query) throws SQLException {
         // do nothing
     }
 
@@ -470,6 +471,10 @@ public abstract class AbstractDriverDefinition implements DriverDefinition {
         return quotedValue.toString();
     }
 
+    public String quoteByteArray(IRubyObject connection, IRubyObject value) {
+        return quoteString(value.asJavaString());
+    }
+
     public String statementToString(Statement s) {
         return s.toString();
     }</diff>
      <filename>do_jdbc/src/main/java/data_objects/drivers/AbstractDriverDefinition.java</filename>
    </modified>
    <modified>
      <diff>@@ -134,7 +134,8 @@ public interface DriverDefinition {
      *
      * @return
      */
-    public void afterConnectionCallback(Connection connection, Map&lt;String, String&gt; query) throws SQLException;
+    public void afterConnectionCallback(IRubyObject doConn, Connection conn,
+            Map&lt;String, String&gt; query) throws SQLException;
 
     /**
      * If the driver supports setting connection encodings, specify the appropriate
@@ -158,6 +159,7 @@ public interface DriverDefinition {
             String url, Properties props) throws SQLException;
 
     public String quoteString(String str);
+    public String quoteByteArray(IRubyObject connection, IRubyObject value);
 
     public String statementToString(Statement s);
 </diff>
      <filename>do_jdbc/src/main/java/data_objects/drivers/DriverDefinition.java</filename>
    </modified>
    <modified>
      <diff>@@ -177,7 +177,7 @@ public class OracleDriverDefinition extends AbstractDriverDefinition {
     }
 
     @Override
-    public void afterConnectionCallback(Connection conn, Map&lt;String, String&gt; query)
+    public void afterConnectionCallback(IRubyObject doConn, Connection conn, Map&lt;String, String&gt; query)
             throws SQLException {
         exec(conn, &quot;alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'&quot;);
         exec(conn, &quot;alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF'&quot;);</diff>
      <filename>do_oracle/ext-java/src/main/java/do_oracle/OracleDriverDefinition.java</filename>
    </modified>
    <modified>
      <diff>@@ -1,15 +1,20 @@
 package do_postgres;
 
-import data_objects.drivers.AbstractDriverDefinition;
-import data_objects.RubyType;
-
-import java.util.Properties;
+import java.sql.Connection;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.sql.Types;
+import java.util.Map;
 
-import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.RubyBoolean;
 import org.jruby.RubyString;
+import org.jruby.runtime.builtin.IRubyObject;
+
+import data_objects.RubyType;
+import data_objects.drivers.AbstractDriverDefinition;
+import data_objects.util.JDBCUtil;
 
 public class PostgresDriverDefinition extends AbstractDriverDefinition {
 
@@ -65,4 +70,86 @@ public class PostgresDriverDefinition extends AbstractDriverDefinition {
         }
     }
 
+    @Override
+    public void afterConnectionCallback(IRubyObject doConn,
+            Connection conn, Map&lt;String, String&gt; query) throws SQLException {
+        checkStandardConformingStrings(doConn, conn);
+    }
+
+    private void checkStandardConformingStrings(IRubyObject doConn, Connection conn) throws SQLException {
+        Statement st = null;
+        boolean standardConformingStrings = false;
+        try {
+            st = conn.createStatement();
+            ResultSet rs = st.executeQuery(&quot;SHOW standard_conforming_strings&quot;);
+            if (rs.next()) {
+                standardConformingStrings = rs.getString(1).equals(&quot;on&quot;);
+            }
+        } catch (SQLException e) {
+            // Ignore. It must be an old server that doesn't support standard_conforming_strings
+        } finally {
+            JDBCUtil.close(st);
+        }
+
+        getObjectAdapter().setInstanceVariable(doConn, &quot;@standard_conforming_strings&quot;,
+            RubyBoolean.newBoolean(doConn.getRuntime(), standardConformingStrings));
+    }
+
+    @Override
+    public String quoteByteArray(IRubyObject doConn, IRubyObject value) {
+        boolean stdStrings = getObjectAdapter().getInstanceVariable(doConn, &quot;@standard_conforming_strings&quot;).isTrue();
+        byte[] bytes = value.asString().getBytes();
+
+        return escapeBytes(stdStrings, bytes);
+    }
+
+    private String escapeBytes(boolean stdStrings, byte[] bytes) {
+        char[] output = new char[calcEscapedLength(stdStrings, bytes)];
+        int offset = 1;
+        output[0] = '\'';
+        for (int b : bytes) {
+            b &amp;= 0xff;
+            if (b &lt; 0x20 || b &gt; 0x7e) {
+                if (! stdStrings) {
+                    output[offset++] = '\\';
+                }
+                output[offset++] = '\\';
+                output[offset++] = (char)((b &gt;&gt; 6) + '0');
+                output[offset++] = (char)(((b &gt;&gt; 3) &amp; 07) + '0');
+                output[offset++] = (char)((b &amp; 07) + '0');
+            } else if (b == '\'') {
+                output[offset++] = '\\';
+                output[offset++] = '\\';
+            } else if (b == '\\') {
+                if (! stdStrings) {
+                    output[offset++] = '\\';
+                    output[offset++] = '\\';
+                }
+                output[offset++] = '\\';
+                output[offset++] = '\\';
+            } else {
+                output[offset++] = (char)b;
+            }
+        }
+        output[offset++] = '\'';
+        return new String(output);
+    }
+
+    private int calcEscapedLength(boolean stdStrings, byte[] bytes) {
+        int length = 2;
+        int backSlashLength = stdStrings ? 1 : 2;
+        for (int b : bytes) {
+            b &amp;= 0xff;
+            if (b &lt; 0x20 || b &gt; 0x7e) {
+                length += backSlashLength + 3;
+            } else if (b == '\'') {
+                length += 2;
+            } else if (b == '\\') {
+                length += backSlashLength + backSlashLength;
+            } else {
+                length++;
+            }
+        }
+        return length;
+    }
 }</diff>
      <filename>do_postgres/ext-java/src/main/java/do_postgres/PostgresDriverDefinition.java</filename>
    </modified>
    <modified>
      <diff>@@ -16,4 +16,18 @@ describe DataObjects::Postgres::Connection do
 
   it_should_behave_like 'a Connection'
   it_should_behave_like 'a Connection with authentication support'
+
+  describe &quot;byte array quoting&quot; do
+    it &quot;should properly escape non-printable ASCII characters&quot; do
+      @connection.quote_byte_array(&quot;\001&quot;).should match(/'\\?\\001'/)
+    end
+
+    it &quot;should properly escape bytes with the high bit set&quot; do
+      @connection.quote_byte_array(&quot;\210&quot;).should match(/'\\?\\210'/)
+    end
+
+    it &quot;should not escape printable ASCII characters&quot; do
+      @connection.quote_byte_array(&quot;a&quot;).should eql(&quot;'a'&quot;)
+    end
+  end
 end</diff>
      <filename>do_postgres/spec/connection_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a19e4dbbe07c970efe535a64883506521dafd5c5</id>
    </parent>
  </parents>
  <author>
    <name>Peter Brant</name>
    <email>peter.brant@gmail.com</email>
  </author>
  <url>http://github.com/datamapper/do/commit/2733161fa64b19cb69bc9558236b3402866e30db</url>
  <id>2733161fa64b19cb69bc9558236b3402866e30db</id>
  <committed-date>2009-10-03T02:41:37-07:00</committed-date>
  <authored-date>2009-10-01T18:49:40-07:00</authored-date>
  <message>Implement quote_byte_array for Postgres

It is essentially a translation of PQescapeByteaConn from libpq to Java.
See the libpq documentation for more information.

The standard_conforming_strings run-time parameter is queried when a
connection is made and used for subsequent quote_byte_array
invocations.</message>
  <tree>03dca6aeacc6859df27103c10ebcc85857f95c0d</tree>
  <committer>
    <name>Alex Coles</name>
    <email>alex@alexcolesportfolio.com</email>
  </committer>
</commit>
