Jason LaRiviere wrote:
> I'm on board; a couple notes:
> http://ruby.scripting.ca/postgres/ appears to be the homepage for the
> project, and offers a snapshot dated 2005.12.21. 
> 
> http://rubyforge.org/frs/download.php/9553 offers a snapshot dated
> 2006.04.06. This package forms the basis for the openbsd port, and will
> be the one I will be patching against and testing. If all is well, I
> will submit an updated port for openbsd including your patch.
> 
> The project homepage also specifies that `this library works with
> PostgreSQL 6.4-8.1', and the macbook is running postgresql 8.2.1. This
> may, or may not have something to do with it's refusal to work. :p
> 
> I will confirm this with an update to pgsql 8.2.1 on the openbsd machines
> and get back to you.

Find attatched a diff that applies cleanly to the 2006.04.06 source.
Also, all teh cool kids are using unified diffs. :p

It builds just fine. Further testing is pending...

-- 
GPG/PGP key ID: 0x3A410DBD | http://pgp.mit.edu
7B3F 4505 7D9A 7FDE 83C9  52C2 4909 59B9 3A41 0DBD
--- ruby-postgres.orig/postgres.c	Thu Apr  6 12:28:10 2006
+++ ruby-postgres/postgres.c	Sat Jan 20 19:57:22 2007
@@ -107,6 +107,7 @@
 }
 
 static int build_key_value_string_i(VALUE key, VALUE value, VALUE result);
+static PGconn *get_pgconn(VALUE obj);
 
 static PGconn *
 try_connectdb(arg)
@@ -199,16 +200,11 @@
     return fact;
 }
 
-static VALUE format_array_element(VALUE obj);
-
 static VALUE
 pgconn_s_format(self, obj)
     VALUE self;
     VALUE obj;
 {
-    VALUE result;
-    int tainted;
-    long i;
 
     switch(TYPE(obj)) {
     case T_STRING:
@@ -224,19 +220,6 @@
     case T_NIL:
       return rb_str_new2("NULL");
 
-    case T_ARRAY:
-      result = rb_str_buf_new2("{");
-      tainted = OBJ_TAINTED(obj);
-      for (i = 0; i < RARRAY(obj)->len; i++) {
-          VALUE element = format_array_element(RARRAY(obj)->ptr[i]);
-          if (OBJ_TAINTED(RARRAY(obj)->ptr[i])) tainted = Qtrue;
-          if (i > 0) rb_str_buf_cat2(result, ", ");
-          rb_str_buf_append(result, element);
-      }
-      rb_str_buf_cat2(result, "}");
-      if (tainted) OBJ_TAINT(result);
-      return result;
-
     default:
       if (CLASS_OF(obj) == rb_cBigDecimal) {
           return rb_funcall(obj, rb_intern("to_s"), 1, rb_str_new2("F"));
@@ -249,16 +232,44 @@
     }
 }
 
+
+/*
+ * call-seq:
+ *    PGconn.quote( obj )
+ *    PGconn.quote( obj ) { |obj| ... }
+ *    PGconn.format( obj )
+ *    PGconn.format( obj ) { |obj| ... }
+ * 
+ * If _obj_ is a Number, String, Array, +nil+, +true+, or +false+ then
+ * #quote returns a String representation of that object safe for use in PostgreSQL.
+ * 
+ * If _obj_ is not one of the above classes and a block is supplied to #quote,
+ * the block is invoked, passing along the object. The return value from the
+ * block is returned as a string.
+ *
+ * If _obj_ is not one of the recognized classes andno block is supplied,
+ * a PGError is raised.
+ */
 static VALUE
-format_array_element(obj)
-    VALUE obj;
+pgconn_s_quote(self, obj)
+    VALUE self, obj;
 {
+    char* quoted;
+    int size;
+    VALUE result;
+
     if (TYPE(obj) == T_STRING) {
-        obj = rb_funcall(obj, rb_intern("gsub"), 2, rb_reg_new("(?=[\\\\\"])", 9, 0), rb_str_new2("\\"));
-        return rb_funcall(obj, rb_intern("gsub!"), 2, rb_reg_new("^|$", 3, 0), rb_str_new2("\""));
+        /* length * 2 because every char could require escaping */
+        /* + 2 for the quotes, + 1 for the null terminator */
+        quoted = ALLOCA_N(char, RSTRING(obj)->len * 2 + 2 + 1);
+        size = PQescapeString(quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len);
+        *quoted = *(quoted + size + 1) = SINGLE_QUOTE;
+        result = rb_str_new(quoted, size + 2);
+        OBJ_INFECT(result, obj);
+        return result;
     }
     else {
-        return pgconn_s_format(rb_cPGconn, obj);
+        return pgconn_s_format(self, obj);
     }
 }
 
@@ -280,18 +291,18 @@
  * a PGError is raised.
  */
 static VALUE
-pgconn_s_quote(self, obj)
+pgconn_quote(self, obj)
     VALUE self, obj;
 {
     char* quoted;
-    int size;
+    int size,error;
     VALUE result;
 
     if (TYPE(obj) == T_STRING) {
         /* length * 2 because every char could require escaping */
         /* + 2 for the quotes, + 1 for the null terminator */
         quoted = ALLOCA_N(char, RSTRING(obj)->len * 2 + 2 + 1);
-        size = PQescapeString(quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len);
+        size = PQescapeStringConn(get_pgconn(self),quoted + 1, RSTRING(obj)->ptr, RSTRING(obj)->len, &error);
         *quoted = *(quoted + size + 1) = SINGLE_QUOTE;
         result = rb_str_new(quoted, size + 2);
         OBJ_INFECT(result, obj);
@@ -302,6 +313,31 @@
     }
 }
 
+static VALUE
+pgconn_s_quote_connstr(string)
+    VALUE string;
+{
+    char *str,*ptr;
+    int i,j=0,len;
+    VALUE result;
+
+    Check_Type(string, T_STRING);
+    
+	ptr = RSTRING(string)->ptr;
+	len = RSTRING(string)->len;
+    str = ALLOCA_N(char, len * 2 + 2 + 1);
+	str[j++] = '\'';
+	for(i = 0; i < len; i++) {
+		if(ptr[i] == '\'' || ptr[i] == '\\')
+			str[j++] = '\\';
+		str[j++] = ptr[i];	
+	}
+	str[j++] = '\'';
+    result = rb_str_new(str, j);
+    OBJ_INFECT(result, string);
+    return result;
+}
+
 static int
 build_key_value_string_i(key, value, result)
     VALUE key, value, result;
@@ -310,15 +346,46 @@
     if (key == Qundef) return ST_CONTINUE;
     key_value = (TYPE(key) == T_STRING ? rb_str_dup(key) : rb_obj_as_string(key));
     rb_str_cat(key_value, "=", 1);
-    rb_str_concat(key_value, pgconn_s_quote(rb_cPGconn, value));
+    rb_str_concat(key_value, pgconn_s_quote_connstr(value));
     rb_ary_push(result, key_value);
     return ST_CONTINUE;
 }
 
 /*
  * call-seq:
- *    PGconn.escape( str )
+ *    PGconn.quote_ident( str )
  *
+ * Returns a SQL-safe identifier.
+ */
+static VALUE
+pgconn_s_quote_ident(self, string)
+    VALUE self;
+    VALUE string;
+{
+    char *str,*ptr;
+    int i,j=0,len;
+    VALUE result;
+
+    Check_Type(string, T_STRING);
+    
+	ptr = RSTRING(string)->ptr;
+	len = RSTRING(string)->len;
+    str = ALLOCA_N(char, len * 2 + 2 + 1);
+	str[j++] = '"';
+	for(i = 0; i < len; i++) {
+		if(ptr[i] == '"')
+			str[j++] = '"';
+		else if(ptr[i] == '\0')
+			rb_raise(rb_ePGError, "Identifier cannot contain NULL bytes");
+		str[j++] = ptr[i];	
+	}
+	str[j++] = '"';
+    result = rb_str_new(str, j);
+    OBJ_INFECT(result, string);
+    return result;
+}
+
+/*
  * Returns a SQL-safe version of the String _str_. Unlike #quote, does not wrap the String in '...'.
  */
 static VALUE
@@ -326,7 +393,7 @@
     VALUE self;
     VALUE string;
 {
-    char* escaped;
+    char *escaped;
     int size;
     VALUE result;
 
@@ -340,6 +407,27 @@
 }
 
 /*
+ * Returns a SQL-safe version of the String _str_. Unlike #quote, does not wrap the String in '...'.
+ */
+static VALUE
+pgconn_escape(self, string)
+    VALUE self;
+    VALUE string;
+{
+    char *escaped;
+    int size,error;
+    VALUE result;
+
+    Check_Type(string, T_STRING);
+    
+    escaped = ALLOCA_N(char, RSTRING(string)->len * 2 + 1);
+    size = PQescapeStringConn(get_pgconn(self),escaped, RSTRING(string)->ptr, RSTRING(string)->len, &error);
+    result = rb_str_new(escaped, size);
+    OBJ_INFECT(result, string);
+    return result;
+}
+
+/*
  * call-seq:
  *   PGconn.escape_bytea( obj )
  *
@@ -379,6 +467,44 @@
 
 /*
  * call-seq:
+ *   PGconn.escape_bytea( obj )
+ *
+ * Escapes binary data for use within an SQL command with the type +bytea+.
+ * 
+ * Certain byte values must be escaped (but all byte values may be escaped)
+ * when used as part of a +bytea+ literal in an SQL statement. In general, to
+ * escape a byte, it is converted into the three digit octal number equal to
+ * the octet value, and preceded by two backslashes. The single quote (') and
+ * backslash (\) characters have special alternative escape sequences.
+ * #escape_bytea performs this operation, escaping only the minimally required bytes.
+ * 
+ * See the PostgreSQL documentation on PQescapeBytea[http://www.postgresql.org/docs/current/interactive/libpq-exec.html#LIBPQ-EXEC-ESCAPE-BYTEA] for more information.
+ */
+static VALUE
+pgconn_escape_bytea(self, obj)
+    VALUE self;
+    VALUE obj;
+{
+    char *from, *to;
+    size_t from_len, to_len;
+    VALUE ret;
+    
+    Check_Type(obj, T_STRING);
+    from      = RSTRING(obj)->ptr;
+    from_len  = RSTRING(obj)->len;
+    
+    to = (char *)PQescapeByteaConn(get_pgconn(self),from, from_len, &to_len);
+    
+    ret = rb_str_new(to, to_len - 1);
+    OBJ_INFECT(ret, obj);
+    
+    PQfreemem(to);
+    
+    return ret;
+}
+
+/*
+ * call-seq:
  *   PGconn.unescape_bytea( obj )
  *
  * Converts an escaped string representation of binary data into binary data --- the
@@ -643,7 +769,7 @@
 
     Check_Type(str, T_STRING);
         
-    while ((result = PQgetResult(conn))) {
+    while ((result = PQgetResult(conn)) != NULL) {
         PQclear(result);
     }
 
@@ -2558,6 +2684,7 @@
     rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
     rb_define_singleton_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
     rb_define_singleton_method(rb_cPGconn, "translate_results=", pgconn_s_translate_results_set, 1);
+    rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
 
     rb_define_const(rb_cPGconn, "CONNECTION_OK", INT2FIX(CONNECTION_OK));
     rb_define_const(rb_cPGconn, "CONNECTION_BAD", INT2FIX(CONNECTION_BAD));
@@ -2592,6 +2719,13 @@
     rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
     rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0);
     rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
+    rb_define_method(rb_cPGconn, "escape", pgconn_escape, 1);
+    rb_define_method(rb_cPGconn, "escape_bytea", pgconn_escape_bytea, 1);
+    rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
+    rb_define_method(rb_cPGconn, "quote", pgconn_quote, 1);
+    rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
+    rb_define_alias(rb_cPGconn, "format", "quote");
+
     /* following line is for rdoc */
     /* rb_define_method(rb_cPGconn, "lastval", pgconn_lastval, 0); */