Author: machack666
Date: Fri Oct  8 22:33:58 2010
New Revision: 14471

Modified:
   DBD-Pg/trunk/quote.c
   DBD-Pg/trunk/t/03dbmethod.t
   DBD-Pg/trunk/t/06bytea.t

Log:
Support dequoting PostgreSQL 9.0 "hex" BYTEA output format

In PostgreSQL 9.0, the default BYTEA output format has changed from
octal escapes for non-printable-ascii characters to encoding the whole
value in hex (with a leading "\x" to distinguish the two).

This also removes papering-over of the lack of dequoting from
t/03dbmethod.t and extends t/06bytea.t to cover both output formats.

Modified: DBD-Pg/trunk/quote.c
==============================================================================
--- DBD-Pg/trunk/quote.c        (original)
+++ DBD-Pg/trunk/quote.c        Fri Oct  8 22:33:58 2010
@@ -442,7 +442,7 @@
 
 
 
-void dequote_bytea(char *string, STRLEN *retlen, int estring)
+static void _dequote_bytea_escape(char *string, STRLEN *retlen, int estring)
 {
        dTHX;
        char *result;
@@ -482,6 +482,58 @@
        return;
 }
 
+static int _decode_hex_digit(char digit)
+{
+       dTHX;
+       if (digit >= '0' && digit <= '9')
+               return digit - '0';
+       if (digit >= 'a' && digit <= 'f')
+               return 10 + digit - 'a';
+       if (digit >= 'A' && digit <= 'F')
+               return 10 + digit - 'A';
+
+       return -1;
+}
+
+static void _dequote_bytea_hex(char *string, STRLEN *retlen, int estring)
+{
+       dTHX;
+       char *result;
+
+       (*retlen) = 0;
+
+       if (NULL == string)
+               return;
+
+       result = string;
+
+       while (*string != '\0') {
+               int digit1, digit2;
+               digit1 = _decode_hex_digit(*string);
+               digit2 = _decode_hex_digit(*(string+1));
+               if (digit1 >= 0 && digit2 >= 0) {
+                       *result++ = 16 * digit1 + digit2;
+                       (*retlen)++;
+               }
+               string += 2;
+       }
+       *result = '\0';
+       return;
+}
+
+void dequote_bytea(char *string, STRLEN *retlen, int estring)
+{
+       dTHX;
+
+       if (NULL == string)
+               return;
+
+       if ('\\' == *string && 'x' == *(string+1))
+               return _dequote_bytea_hex(string, retlen, estring);
+       else
+               return _dequote_bytea_escape(string, retlen, estring);
+}
+
 /*
        This one is not used in PG, but since we have a quote_sql_binary,
        it might be nice to let people go the other way too. Say when talking

Modified: DBD-Pg/trunk/t/03dbmethod.t
==============================================================================
--- DBD-Pg/trunk/t/03dbmethod.t (original)
+++ DBD-Pg/trunk/t/03dbmethod.t Fri Oct  8 22:33:58 2010
@@ -1402,8 +1402,6 @@
 ok (!$result, $t);
 $dbh->rollback();
 
-my $abctext = $pgversion >= 80500 ? 'x6162630a646566' : "abc\ndef";
-
 SKIP: {
 
        eval {
@@ -1422,7 +1420,7 @@
        $t='DB handle method "pg_lo_import" inserts correct data';
        $SQL = "SELECT data FROM pg_largeobject where loid = $handle";
        $info = $dbh->selectall_arrayref($SQL)->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
        $dbh->commit();
 
   SKIP: {
@@ -1444,7 +1442,7 @@
                $t='DB handle method "pg_lo_import_with_oid" inserts correct 
data';
                $SQL = "SELECT data FROM pg_largeobject where loid = $thandle";
                $info = $dbh->selectall_arrayref($SQL)->[0][0];
-               is_deeply ($info, $abctext, $t);
+               is_deeply ($info, "abc\ndef", $t);
 
                $t='DB handle method "pg_lo_import_with_oid" fails when given 
already used number';
                eval {
@@ -1558,7 +1556,7 @@
        $sth = $dbh->prepare($SQL);
        $sth->execute($handle);
        $info = $sth->fetchall_arrayref()->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
 
        $t='DB handle method "pg_lo_import" works (AutoCommit on, begin_work 
called, no command)';
        $dbh->begin_work();
@@ -1566,7 +1564,7 @@
        ok ($handle, $t);
        $sth->execute($handle);
        $info = $sth->fetchall_arrayref()->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
        $dbh->rollback();
 
        $t='DB handle method "pg_lo_import" works (AutoCommit on, begin_work 
called, no command, rollback)';
@@ -1585,7 +1583,7 @@
        ok ($handle, $t);
        $sth->execute($handle);
        $info = $sth->fetchall_arrayref()->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
        $dbh->rollback();
 
        $t='DB handle method "pg_lo_import" works (AutoCommit on, begin_work 
called, second command, rollback)';
@@ -1605,7 +1603,7 @@
        ok ($handle, $t);
        $sth->execute($handle);
        $info = $sth->fetchall_arrayref()->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
 
        $t='DB handle method "pg_lo_import" works (AutoCommit not on, second 
command)';
        $dbh->rollback();
@@ -1614,7 +1612,7 @@
        ok ($handle, $t);
        $sth->execute($handle);
        $info = $sth->fetchall_arrayref()->[0][0];
-       is_deeply ($info, $abctext, $t);
+       is_deeply ($info, "abc\ndef", $t);
 
        unlink $filename;
        $dbh->{AutoCommit} = 1;

Modified: DBD-Pg/trunk/t/06bytea.t
==============================================================================
--- DBD-Pg/trunk/t/06bytea.t    (original)
+++ DBD-Pg/trunk/t/06bytea.t    Fri Oct  8 22:33:58 2010
@@ -17,7 +17,7 @@
 if (! $dbh) {
        plan skip_all => 'Connection to database failed, cannot continue 
testing';
 }
-plan tests => 11;
+plan tests => 16;
 
 isnt ($dbh, undef, 'Connect to database for bytea testing');
 
@@ -26,10 +26,6 @@
        $dbh->do('SET escape_string_warning = false');
 }
 
-if ($pgversion >= 90000) {
-       $dbh->do(q{SET bytea_output = 'escape'});
-}
-
 my ($sth, $t);
 
 $sth = $dbh->prepare(q{INSERT INTO dbd_pg_test (id,bytetest) VALUES (?,?)});
@@ -53,31 +49,48 @@
 $sth->{pg_server_prepare} = 1;
 ok ($sth->execute(404, $binary_out), $t);
 
-$t='Received correct text from BYTEA column with backslashes';
-$sth = $dbh->prepare(q{SELECT bytetest FROM dbd_pg_test WHERE id=?});
-$sth->execute(400);
-my $byte = $sth->fetchall_arrayref()->[0][0];
-is ($byte, 'aa\bb\cc\\\0dd\\', $t);
-
-$t='Received correct text from BYTEA column with quote';
-$sth->execute(402);
-$byte = $sth->fetchall_arrayref()->[0][0];
-is ($byte, '\'', $t);
-
-$t='Ensure proper handling of high bit characters';
-$sth->execute(403);
-($binary_in) = $sth->fetchrow_array();
-ok ($binary_in eq $binary_out, $t);
-$sth->execute(404);
-($binary_in) = $sth->fetchrow_array();
-ok ($binary_in eq $binary_out, $t);
-
-$t='quote properly handles bytea strings';
-my $string = "abc\123\\def\0ghi";
-my $result = $dbh->quote($string, { pg_type => PG_BYTEA });
-my $E = $pgversion >= 80100 ? q{E} : q{};
-my $expected = qq{${E}'abc\123\\\\\\\\def\\\\000ghi'};
-is ($result, $expected, $t);
+my @output;
+if ($pgversion >= 90000) {
+       @output = qw(hex escape);
+}
+else {
+       @output = (undef);
+       SKIP: { skip 'No BYTEA output format setting before 9.0', 5 }
+}
+
+for my $output (@output) {
+       $dbh->do(qq{SET bytea_output = '$output'}) if $output;
+
+       $t='Received correct text from BYTEA column with backslashes';
+       $t.=" ($output output)" if $output;
+       $sth = $dbh->prepare(q{SELECT bytetest FROM dbd_pg_test WHERE id=?});
+       $sth->execute(400);
+       my $byte = $sth->fetchall_arrayref()->[0][0];
+       is ($byte, 'aa\bb\cc\\\0dd\\', $t);
+
+       $t='Received correct text from BYTEA column with quote';
+       $t.=" ($output output)" if $output;
+       $sth->execute(402);
+       $byte = $sth->fetchall_arrayref()->[0][0];
+       is ($byte, '\'', $t);
+
+       $t='Ensure proper handling of high bit characters';
+       $t.=" ($output output)" if $output;
+       $sth->execute(403);
+       ($binary_in) = $sth->fetchrow_array();
+       ok ($binary_in eq $binary_out, $t);
+       $sth->execute(404);
+       ($binary_in) = $sth->fetchrow_array();
+       ok ($binary_in eq $binary_out, $t);
+
+       $t='quote properly handles bytea strings';
+       $t.=" ($output output)" if $output;
+       my $string = "abc\123\\def\0ghi";
+       my $result = $dbh->quote($string, { pg_type => PG_BYTEA });
+       my $E = $pgversion >= 80100 ? q{E} : q{};
+       my $expected = qq{${E}'abc\123\\\\\\\\def\\\\000ghi'};
+       is ($result, $expected, $t);
+}
 
 $sth->finish();
 

Reply via email to