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();