Edmund & DBI folks,

Please find enclosed a patch for DBD::Pg. It vastly simplifies how the
quote() method works, making it faster and more precise, and eliminates
the need for POSIX::isprint(). I've discussed this method with the
PostgreSQL developers, and they agree that this simplified patch is all
that is needed to support the BYTEA data type. I ask that you consider
adding it to the next release of DBD::Pg. To apply the patch, cd to the
directory with Pg.pm in it, and simply

  patch -Np1 Pg.pm.patch

Discussion of the patch with the PostgreSQL developers may be found
here:

http://www.geocrawler.com/mail/thread.php3?subject=%5BGENERAL%5D+DBD%3A%3APg+BYTEA+Character+Escaping&list=12

Comments are welcome.

Regards,

David

-- 
David Wheeler                                     AIM: dwTheory
[EMAIL PROTECTED]                                 ICQ: 15726394
                                               Yahoo!: dew7e
                                               Jabber: [EMAIL PROTECTED]
diff -Naur old/Pg.pm new/Pg.pm
--- old/Pg.pm	Tue Nov 27 08:28:17 2001
+++ new/Pg.pm	Tue Nov 27 08:28:34 2001
@@ -104,7 +104,17 @@
 
 {   package DBD::Pg::db; # ====== DATABASE ======
     use strict;
-    use POSIX(qw(isprint)); # necessary for quote()
+
+    # Characters that need to be escaped by quote().
+    my %esc = ( "'"  => '\\047', # '\\' . sprintf("%03o", ord("'")), # ISO SQL 2
+                '\\' => '\\134', # '\\' . sprintf("%03o", ord("\\")),
+                "\0" => '\\000'  # '\\' . sprintf("%03o", ord("\0")),
+              );
+
+    # Set up lookup for SQL types we don't want to escape.
+    my @no_escape;
+    grep { $no_escape[$_] = 1 } DBI::SQL_INTEGER, DBI::SQL_SMALLINT, DBI::SQL_DECIMAL,
+      DBI::SQL_FLOAT, DBI::SQL_REAL, DBI::SQL_DOUBLE, DBI::SQL_NUMERIC;
 
     sub prepare {
         my($dbh, $statement, @attribs)= @_;
@@ -341,48 +351,13 @@
 
     sub quote {
         my ($dbh, $str, $data_type) = @_;
-
         return "NULL" unless defined $str;
 
-        unless ($data_type) {
-            $str =~ s/'/''/g;           # ISO SQL2
-            # In addition to the DBI method it doubles also the
-            # backslash, because PostgreSQL treats a backslash as an
-            # escape character.
-            $str =~ s/\\/\\\\/g;
-            return "'$str'";
-        }
-
-        # Optimise for standard numerics which need no quotes
-        return $str if $data_type == DBI::SQL_INTEGER
-                    || $data_type == DBI::SQL_SMALLINT
-                    || $data_type == DBI::SQL_DECIMAL
-                    || $data_type == DBI::SQL_FLOAT
-                    || $data_type == DBI::SQL_REAL
-                    || $data_type == DBI::SQL_DOUBLE
-                    || $data_type == DBI::SQL_NUMERIC;
-        my $ti = $dbh->type_info($data_type);
-        # XXX needs checking
-        my $lp = $ti ? $ti->{LITERAL_PREFIX} || "" : "'";
-        my $ls = $ti ? $ti->{LITERAL_SUFFIX} || "" : "'";
-        # XXX don't know what the standard says about escaping
-        # in the 'general case' (where $lp != "'").
-        # So we just do this and hope:
-        $str =~ s/$lp/$lp$lp/g  
-            if $lp && $lp eq $ls && ($lp eq "'" || $lp eq '"');
-        # also, escape the backslashes, always
-        $str =~ s/\\/\\\\/g;
-        # if the type is SQL_BINARY, escape the non-printable chars
-        if ($data_type == DBI::SQL_BINARY ||
-            $data_type == DBI::SQL_VARBINARY ||
-            $data_type == DBI::SQL_LONGVARBINARY) {
-            $str=join("", map { isprint($_)?$_:'\\'.sprintf("%03o",ord($_)) } 
-                          split //, $str);
-        }
-        return "$lp$str$ls";
+	return $str if $data_type && $no_escape[$data_type];
+	$str =~ s/(['\\\0])/$esc{$&}/g;
+	return "'$str'";
     }
 }
-
 
 {   package DBD::Pg::st; # ====== STATEMENT ======
 

Reply via email to