Skip Menu |

This queue is for tickets about the DBD-Pg CPAN distribution.

Report information
The Basics
Id: 58552
Status: resolved
Priority: 0/
Queue: DBD-Pg

People
Owner: Nobody in particular
Requestors: noah [...] leadboat.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 2.17.1
Fixed in: 2.19.0



Subject: Fix marshalling of arrays containing ', ", and/or \
Versions 2.14.0 and 2.15.0 included some fixes for arrays and ->quote, but there a few more holes to plug. Try: use DBI; $dbh = DBI->connect(undef, undef, undef, {RaiseError => 1, PrintError => 0, AutoCommit => 1}); for ('a\\b', 'a\'b') { print "$_ => ", ($dbh->selectrow_array('SELECT ?::text[]', {}, [$_]))[0]->[0], "\n"; print "$_ => ", ($dbh->selectrow_array('SELECT ' . $dbh->quote([$_]). '::text[]'))[0]->[0], "\n"; } pg_stringify_array is doing some of the jobs of quote_string (prepend/append single-quotes, double backslashes) but missing others (double single-quotes, possibly add the escape string prefix). The attached patch changes `quote' to pass the product of pg_stringify_array through the standard quoting mechanism, and it changes pg_stringify_array to only format the string for the needs of anyarray_in, removing it from the quoted string business. The relevant test group, 09arrays.t, checks an expected value for the server's raw array output by storing and retrieving the array under pg_expand_array=0. It checks an expected output of $dbh->quote directly and by converting it to a Perl array for comparison to a value retrieved under pg_expand_array=1. The tests passed because those expectations were incorrect. This patch keeps the first test (with corrected expectations) and discards the second. In its place, I attempt a dynamic INSERT based on $dbh->quote output, and I directly compare the Perl array provided to $sth->execute or $dbh->quote to the retrieved value. For some reason, the code in that area was checking each expected error message twice; I changed it to check only once, but perhaps I missed something in so doing. Since this change removes escape_string_warning damage from the array tests, I also remove the code disabling that. Applying just the 09arrays.t changes will illustrate the failure points in the current implementation. Unfortunately, this is another compatibility break. However, I inasmuch as it breaks compatibility, it brings $sth->bind_param and $dbh->quote closer to their contracts for the affected data. Thanks, nm
Subject: dbdpg-array-backslash.patch
Index: dbdimp.c =================================================================== --- dbdimp.c (revision 14181) +++ dbdimp.c (working copy) @@ -2259,7 +2259,7 @@ } else if (SvTYPE(SvRV(newvalue)) == SVt_PVAV) { SV * quotedval; - quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version, 0); + quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version); currph->valuelen = sv_len(quotedval); Renew(currph->value, currph->valuelen+1, char); /* freed in dbd_st_destroy */ currph->value = SvUTF8(quotedval) ? SvPVutf8_nolen(quotedval) : SvPV_nolen(quotedval); @@ -2393,7 +2393,7 @@ /* ================================================================== */ -SV * pg_stringify_array(SV *input, const char * array_delim, int server_version, int extraquotes) { +SV * pg_stringify_array(SV *input, const char * array_delim, int server_version) { dTHX; AV * toparr; @@ -2412,14 +2412,12 @@ if (TSTART) TRC(DBILOGFP, "%sBegin pg_stringify_array\n", THEADER); toparr = (AV *) SvRV(input); - value = extraquotes ? newSVpv("'{", 2) : newSVpv("{", 1); + value = newSVpv("{", 1); /* Empty arrays are easy */ if (av_len(toparr) < 0) { av_clear(toparr); sv_catpv(value, "}"); - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (empty)\n", THEADER); return value; } @@ -2489,14 +2487,9 @@ SvUTF8_on(value); string = SvPV(svitem, svlen); while (svlen--) { - - /* If an embedded quote, throw a backslash before it */ - if ('\"' == *string) + /* Escape backslashes and double-quotes. */ + if ('\"' == *string || '\\' == *string) sv_catpvn(value, "\\", 1); - /* If a backslash, double it up */ - if ('\\' == *string) { - sv_catpvn(value, "\\\\\\", 3); - } sv_catpvn(value, string, 1); string++; } @@ -2521,8 +2514,6 @@ for (xy=0; xy<array_depth; xy++) { sv_catpv(value, "}"); } - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (string: %s)\n", THEADER, neatsvpv(value,0)); return value; Index: dbdimp.h =================================================================== --- dbdimp.h (revision 14181) +++ dbdimp.h (working copy) @@ -187,7 +187,7 @@ SV * pg_db_pg_notifies (SV *dbh, imp_dbh_t *imp_dbh); -SV * pg_stringify_array(SV * input, const char * array_delim, int server_version, int extraquotes); +SV * pg_stringify_array(SV * input, const char * array_delim, int server_version); int pg_quickexec (SV *dbh, const char *sql, const int asyncflag); Index: Pg.xs =================================================================== --- Pg.xs (revision 14181) +++ Pg.xs (working copy) @@ -198,15 +198,18 @@ SvGETMAGIC(to_quote_sv); + /* Reject references other than overloaded objects (presumed + stringifiable) and arrays (will make a PostgreSQL array). */ + if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { + if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) + croak("Cannot quote a reference"); + to_quote_sv = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version); + } + /* Null is always returned as "NULL", so we can ignore any type given */ if (!SvOK(to_quote_sv)) { RETVAL = newSVpvn("NULL", 4); } - else if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { - if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) - croak("Cannot quote a reference"); - RETVAL = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version, 1); - } else { sql_type_info_t *type_info; char *quoted; Index: t/09arrays.t =================================================================== --- t/09arrays.t (revision 14181) +++ t/09arrays.t (working copy) @@ -18,7 +18,7 @@ if (! defined $dbh) { plan skip_all => 'Connection to database failed, cannot continue testing'; } -plan tests => 257; +plan tests => 200; isnt ($dbh, undef, 'Connect to database for array testing'); @@ -26,10 +26,6 @@ my $pgversion = $dbh->{pg_server_version}; -if ($pgversion >= 80100) { - $dbh->do('SET escape_string_warning = false'); -} - my $SQL = q{DELETE FROM dbd_pg_test WHERE pname = 'Array Testing'}; my $cleararray = $dbh->prepare($SQL); @@ -62,8 +58,8 @@ is ($@, q{}, $t); $dbh->rollback(); -## Input -## Expected +## Input (eval-able Perl) +## Expected (ERROR or raw PostgreSQL output) ## Name of test my $array_tests = @@ -120,51 +116,51 @@ Unbalanced array [123] -{123} quote: {"123"} +{123} Simple 1-D numeric array ['abc'] -{abc} quote: {"abc"} +{abc} Simple 1-D text array ['a','b,c'] -{a,"b,c"} quote: {"a","b,c"} +{a,"b,c"} Text array with commas and quotes ['a','b,}'] -{a,"b,}"} quote: {"a","b,}"} +{a,"b,}"} Text array with commas, escaped closing brace ['a','b,]'] -{a,"b,]"} quote: {"a","b,]"} +{a,"b,]"} Text array with commas, escaped closing bracket [1,2] -{1,2} quote: {"1","2"} +{1,2} Simple 1-D numeric array [[1]] -{{1}} quote: {{"1"}} +{{1}} Simple 2-D numeric array [[1,2]] -{{1,2}} quote: {{"1","2"}} +{{1,2}} Simple 2-D numeric array [[[1]]] -{{{1}}} quote: {{{"1"}}} +{{{1}}} Simple 3-D numeric array [[["alpha",2],[23,"pop"]]] -{{{alpha,2},{23,pop}}} quote: {{{"alpha","2"},{"23","pop"}}} +{{{alpha,2},{23,pop}}} 3-D mixed array [[[1,2,3],[4,5,"6"],["seven","8","9"]]] -{{{1,2,3},{4,5,6},{seven,8,9}}} quote: {{{"1","2","3"},{"4","5","6"},{"seven","8","9"}}} +{{{1,2,3},{4,5,6},{seven,8,9}}} 3-D mixed array [q{O'RLY?}] -{O'RLY?} quote: {"O'RLY?"} +{O'RLY?} Simple single quote [q{O"RLY?}] @@ -172,19 +168,19 @@ Simple double quote [[q{O"RLY?}],[q|'Ya' - "really"|],[123]] -{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} quote: {{"O\"RLY?"},{"'Ya' - \"really\""},{"123"}} +{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} Many quotes ["Single\\\\Backslash"] -{"Single\\\\\\\\Backslash"} quote: {"Single\\\\\\\\Backslash"} +{"Single\\\\Backslash"} Single backslash testing ["Double\\\\\\\\Backslash"] -{"Double\\\\\\\\\\\\\\\\Backslash"} quote: {"Double\\\\\\\\\\\\\\\\Backslash"} +{"Double\\\\\\\\Backslash"} Double backslash testing [["Test\\\nRun","Quite \"so\""],["back\\\\\\\\slashes are a \"pa\\\\in\"",123] ] -{{"Test\\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"",123}} quote: {{"Test\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"","123"}} +{{"Test\\\nRun","Quite \"so\""},{"back\\\\\\\\slashes are a \"pa\\\\in\"",123}} Escape party - backslash+newline, two + one [undef] @@ -196,25 +192,25 @@ NEED 80200: Simple undef test [[1,2],[undef,3],["four",undef],[undef,undef]] -{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} quote: {{"1","2"},{NULL,"3"},{"four",NULL},{NULL,NULL}} +{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} NEED 80200: Multiple undef test !; ## Note: We silently allow things like this: [[[]],[]] -$dbh->{pg_expand_array} = 0; +sub safe_getarray { + my $ret = eval { + $getarray->execute(); + $getarray->fetchall_arrayref()->[0][0]; + }; + $@ || $ret +} for my $test (split /\n\n/ => $array_tests) { next unless $test =~ /\w/; my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; - } - if ($qexpected !~ /^ERROR/) { - $qexpected = qq{'$qexpected'}; - } + my $perl_input = eval $input; if ($msg =~ s/NEED (\d+):\s*//) { my $ver = $1; @@ -226,88 +222,47 @@ } } - $t="Correct array inserted: $msg : $input"; - $cleararray->execute(); + # INSERT via bind values + $dbh->rollback; eval { - $addarray->execute(eval $input); + $addarray->execute($perl_input); }; if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); + like ($@, qr{$1}, "[bind] Array insert error : $msg : $input"); } else { - is ($@, q{}, "Array worked : $msg : $input"); - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - is ($result, $expected, $t); + is ($@, q{}, "[bind] Array insert success : $msg : $input"); + + $t="[bind][!expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 0; + is (safe_getarray, $expected, $t); + + $t="[bind][expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 1; + is_deeply (safe_getarray, $perl_input, $t); } - $t="Array quote worked : $msg : $input"; + # INSERT via `quote' and dynamic SQL + $dbh->rollback; eval { - $result = $dbh->quote(eval $input ); + $quotearr = $dbh->quote($perl_input); + $SQL = qq{INSERT INTO dbd_pg_test(id,pname,testarray) VALUES (99,'Array Testing',$quotearr)}; + $dbh->do($SQL); }; - if ($qexpected =~ /error:\s+(.+)/i) { + if ($expected =~ /error:\s+(.+)/i) { my $errmsg = $1; $errmsg =~ s/bind/quote/; - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); + like ($@, qr{$errmsg}, "[quote] Array insert error : $msg : $input"); } else { - is ($@, q{}, $t); + is ($@, q{}, "[quote] Array insert success : $msg : $input"); - $t="Correct array quote: $msg : $input"; - is ($result, $qexpected, $t); - } + # No need to recheck !expand case. -} - - -## Same thing, but expand the arrays -$dbh->{pg_expand_array} = 1; - -for my $test (split /\n\n/ => $array_tests) { - next unless $test =~ /\w/; - my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; + $t="[quote][expand] Correct array inserted: $msg : $input"; + is_deeply (safe_getarray, $perl_input, $t); } - if ($msg =~ s/NEED (\d+):\s*//) { - my $ver = $1; - if ($pgversion < $ver) { - SKIP: { - skip ('Cannot test NULL arrays unless version 8.2 or better', 2); - } - next; - } - } - - $t="Array worked : $msg : $input"; - $cleararray->execute(); - eval { - $addarray->execute(eval $input); - }; - if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); - } - else { - is ($@, q{}, $t); - - $t="Correct array inserted: $msg : $input"; - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - $qexpected =~ s/{}/{''}/; - $qexpected =~ y/{}/[]/; - $qexpected =~ s/NULL/undef/g; - if ($msg =~ /closing brace/) { - $qexpected =~ s/]"/}"/; - } - $expected = eval $qexpected; - is_deeply ($result, $expected, $t); - } - if ($msg =~ /STOP/) { warn "Exiting for DEBUGGING. Result is:\n"; warn Dumper $result; @@ -315,7 +270,6 @@ $dbh->disconnect; exit; } - }
hello, i'm with 2.18.1 and quotes of commas and backslash is fine. But, if you try to quote array with single quotes the quote broken, because on 2.15.0 when added single quotes to the end/finish of the string, indeed should be a recurse call to quote with the array string. Because in the first place, you call to quote an array, so quote-char is doble quote. But, the expected result is a string ready to insert to the database, so we need quote this string [that represent the array] "again". however, while it not fixed [it's currently written in C, not fast to [me] fix it] I'm using another sub to fix that: sub quoteStr{ my ($this = $_[0]; my $quote = $_[1]; my $db = [here your DBI->connect object from someware] my $quoted; if (ref $quote eq 'ARRAY'){ # quote the array $quoted = $db->quote($quote); # print "quoted array is $quoted chaging str\n"; # DBD::Pg 2.15.0 fixing # better check $DBD::Pg::VERSION here ? $quoted =~ s/^'//o; $quoted =~ s/'$//o; # *requote* it $quoted = $this->quoteStr($quoted); } else{ $quoted = $db->quote($quote); } return $quoted; } **test** my $array = [[qw /test'test 213/], ["'", " \\ "]]; print Dumper MyClass::quoteStr($array); # prints <<< '{{"test''test","213"},{"''"," , "}}' # ----- so you can do '{{"test''test","213"},{"''"," , "}}'::text[][] and the sintax is fine!
I think I've run into the problem with sinqle quotes and arrays that is mentioned here. We were evaluating an upgrade to 2.18.1 from a much older version, and saw some test failures in our test suite. I think the issue can be illustrated by this simple update to the DBD::Pg test suite, which swaps out a simple value in an array quoting test for a more complex one: diff -rN -u old-DBD-Pg-2.18.1/t/09arrays.t new-DBD-Pg- 2.18.1/t/09arrays.t --- old-DBD-Pg-2.18.1/t/09arrays.t 2011-09-02 14:06:29.000000000 - 0400 +++ new-DBD-Pg-2.18.1/t/09arrays.t 2011-09-02 14:06:29.000000000 - 0400 @@ -54,7 +54,7 @@ $t='Array quoting allows direct insertion into statements'; $SQL = q{INSERT INTO dbd_pg_test (id,testarray2) VALUES }; my $quoteid = $dbh->quote(123); -my $quotearr = $dbh->quote([456]); +my $quotearr = $dbh->quote(["Quote's Test"]); $SQL .= qq{($quoteid, $quotearr)}; eval { $dbh->do($SQL); ####### The result: # Failed test 'Array quoting allows direct insertion into statements' # at t/09arrays.t line 62. # got: 'DBD::Pg::db do failed: ERROR: syntax error at or near "s" # LINE 1: ...d_pg_test (id,testarray2) VALUES ('123', '{"Quote's Test"}') # ^ at t/09arrays.t line 60. # ' # expected: '' # Looks like you failed 1 test of 257. t/09arrays.t ........ Dubious, test returned 1 (wstat 256, 0x100) Failed 1/257 subtests ####### For now, this is blocking our upgrade to a modern DBD::Pg while we evaluate workarounds.
Subject: Fix marshalling of arrays containing ', ", and/or \ (report on trying Noah's patch with my test)
To help move this along, I tried applying Noah's proposed patch to 2.18.1 and running "make test". The patch needed a small refinement to apply. I've attached my revised version of the patch that I used. The result was that the patch passed the entire test suite, plus Noah's new test suite changes, but it *failed* the new test I added, above. So, either Noah or I have the wrong idea about what the quoting behavior should be for arrays, or the code needs further modifications to address Noah's test changes as well as my test addition. Greg: any input here?
Subject: dbdpg-array-backslash-v2.patch
diff -rN -u old-DBD-Pg-2.18.1/Pg.xs new-DBD-Pg-2.18.1/Pg.xs --- old-DBD-Pg-2.18.1/Pg.xs 2011-09-09 09:13:06.000000000 -0400 +++ new-DBD-Pg-2.18.1/Pg.xs 2011-09-09 09:13:06.000000000 -0400 @@ -200,15 +200,18 @@ SvGETMAGIC(to_quote_sv); + /* Reject references other than overloaded objects (presumed + stringifiable) and arrays (will make a PostgreSQL array). */ + if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { + if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) + croak("Cannot quote a reference"); + to_quote_sv = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version); + } + /* Null is always returned as "NULL", so we can ignore any type given */ if (!SvOK(to_quote_sv)) { RETVAL = newSVpvn("NULL", 4); } - else if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { - if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) - croak("Cannot quote a reference"); - RETVAL = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version, 1); - } else { sql_type_info_t *type_info; char *quoted; diff -rN -u old-DBD-Pg-2.18.1/dbdimp.c new-DBD-Pg-2.18.1/dbdimp.c --- old-DBD-Pg-2.18.1/dbdimp.c 2011-09-09 09:13:06.000000000 -0400 +++ new-DBD-Pg-2.18.1/dbdimp.c 2011-09-09 09:13:06.000000000 -0400 @@ -2284,7 +2284,7 @@ } else if (SvTYPE(SvRV(newvalue)) == SVt_PVAV) { SV * quotedval; - quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version, 0); + quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version); currph->valuelen = sv_len(quotedval); Renew(currph->value, currph->valuelen+1, char); /* freed in dbd_st_destroy */ Copy(SvUTF8(quotedval) ? SvPVutf8_nolen(quotedval) : SvPV_nolen(quotedval), @@ -2420,7 +2420,7 @@ /* ================================================================== */ -SV * pg_stringify_array(SV *input, const char * array_delim, int server_version, int extraquotes) { +SV * pg_stringify_array(SV *input, const char * array_delim, int server_version) { dTHX; AV * toparr; @@ -2439,14 +2439,12 @@ if (TSTART) TRC(DBILOGFP, "%sBegin pg_stringify_array\n", THEADER); toparr = (AV *) SvRV(input); - value = extraquotes ? newSVpv("'{", 2) : newSVpv("{", 1); + value = newSVpv("{", 1); /* Empty arrays are easy */ if (av_len(toparr) < 0) { av_clear(toparr); sv_catpv(value, "}"); - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (empty)\n", THEADER); return value; } @@ -2516,14 +2514,9 @@ SvUTF8_on(value); string = SvPV(svitem, stringlength); while (stringlength--) { - - /* If an embedded quote, throw a backslash before it */ - if ('\"' == *string) + /* Escape backslashes and double-quotes. */ + if ('\"' == *string || '\\' == *string) sv_catpvn(value, "\\", 1); - /* If a backslash, double it up */ - if ('\\' == *string) { - sv_catpvn(value, "\\\\\\", 3); - } sv_catpvn(value, string, 1); string++; } @@ -2548,8 +2541,6 @@ for (xy=0; xy<array_depth; xy++) { sv_catpv(value, "}"); } - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (string: %s)\n", THEADER, neatsvpv(value,0)); return value; diff -rN -u old-DBD-Pg-2.18.1/dbdimp.h new-DBD-Pg-2.18.1/dbdimp.h --- old-DBD-Pg-2.18.1/dbdimp.h 2011-09-09 09:13:06.000000000 -0400 +++ new-DBD-Pg-2.18.1/dbdimp.h 2011-09-09 09:13:06.000000000 -0400 @@ -190,7 +190,7 @@ SV * pg_db_pg_notifies (SV *dbh, imp_dbh_t *imp_dbh); -SV * pg_stringify_array(SV * input, const char * array_delim, int server_version, int extraquotes); +SV * pg_stringify_array(SV * input, const char * array_delim, int server_version); int pg_quickexec (SV *dbh, const char *sql, const int asyncflag); diff -rN -u old-DBD-Pg-2.18.1/t/09arrays.t new-DBD-Pg-2.18.1/t/09arrays.t --- old-DBD-Pg-2.18.1/t/09arrays.t 2011-09-09 09:13:06.000000000 -0400 +++ new-DBD-Pg-2.18.1/t/09arrays.t 2011-09-09 09:13:06.000000000 -0400 @@ -18,7 +18,7 @@ if (! $dbh) { plan skip_all => 'Connection to database failed, cannot continue testing'; } -plan tests => 257; +plan tests => 200; isnt ($dbh, undef, 'Connect to database for array testing'); @@ -26,10 +26,6 @@ my $pgversion = $dbh->{pg_server_version}; -if ($pgversion >= 80100) { - $dbh->do('SET escape_string_warning = false'); -} - my $SQL = q{DELETE FROM dbd_pg_test WHERE pname = 'Array Testing'}; my $cleararray = $dbh->prepare($SQL); @@ -54,7 +50,7 @@ $t='Array quoting allows direct insertion into statements'; $SQL = q{INSERT INTO dbd_pg_test (id,testarray2) VALUES }; my $quoteid = $dbh->quote(123); -my $quotearr = $dbh->quote([456]); +my $quotearr = $dbh->quote(["Quote's Test"]); $SQL .= qq{($quoteid, $quotearr)}; eval { $dbh->do($SQL); @@ -62,8 +58,8 @@ is ($@, q{}, $t); $dbh->rollback(); -## Input -## Expected +## Input (eval-able Perl) +## Expected (ERROR or raw PostgreSQL output) ## Name of test my $array_tests = @@ -120,51 +116,51 @@ Unbalanced array [123] -{123} quote: {"123"} +{123} Simple 1-D numeric array ['abc'] -{abc} quote: {"abc"} +{abc} Simple 1-D text array ['a','b,c'] -{a,"b,c"} quote: {"a","b,c"} +{a,"b,c"} Text array with commas and quotes ['a','b,}'] -{a,"b,}"} quote: {"a","b,}"} +{a,"b,}"} Text array with commas, escaped closing brace ['a','b,]'] -{a,"b,]"} quote: {"a","b,]"} +{a,"b,]"} Text array with commas, escaped closing bracket [1,2] -{1,2} quote: {"1","2"} +{1,2} Simple 1-D numeric array [[1]] -{{1}} quote: {{"1"}} +{{1}} Simple 2-D numeric array [[1,2]] -{{1,2}} quote: {{"1","2"}} +{{1,2}} Simple 2-D numeric array [[[1]]] -{{{1}}} quote: {{{"1"}}} +{{{1}}} Simple 3-D numeric array [[["alpha",2],[23,"pop"]]] -{{{alpha,2},{23,pop}}} quote: {{{"alpha","2"},{"23","pop"}}} +{{{alpha,2},{23,pop}}} 3-D mixed array [[[1,2,3],[4,5,"6"],["seven","8","9"]]] -{{{1,2,3},{4,5,6},{seven,8,9}}} quote: {{{"1","2","3"},{"4","5","6"},{"seven","8","9"}}} +{{{1,2,3},{4,5,6},{seven,8,9}}} 3-D mixed array [q{O'RLY?}] -{O'RLY?} quote: {"O'RLY?"} +{O'RLY?} Simple single quote [q{O"RLY?}] @@ -172,19 +168,19 @@ Simple double quote [[q{O"RLY?}],[q|'Ya' - "really"|],[123]] -{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} quote: {{"O\"RLY?"},{"'Ya' - \"really\""},{"123"}} +{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} Many quotes ["Single\\\\Backslash"] -{"Single\\\\\\\\Backslash"} quote: {"Single\\\\\\\\Backslash"} +{"Single\\\\Backslash"} Single backslash testing ["Double\\\\\\\\Backslash"] -{"Double\\\\\\\\\\\\\\\\Backslash"} quote: {"Double\\\\\\\\\\\\\\\\Backslash"} +{"Double\\\\\\\\Backslash"} Double backslash testing [["Test\\\nRun","Quite \"so\""],["back\\\\\\\\slashes are a \"pa\\\\in\"",123] ] -{{"Test\\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"",123}} quote: {{"Test\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"","123"}} +{{"Test\\\nRun","Quite \"so\""},{"back\\\\\\\\slashes are a \"pa\\\\in\"",123}} Escape party - backslash+newline, two + one [undef] @@ -196,25 +192,25 @@ NEED 80200: Simple undef test [[1,2],[undef,3],["four",undef],[undef,undef]] -{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} quote: {{"1","2"},{NULL,"3"},{"four",NULL},{NULL,NULL}} +{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} NEED 80200: Multiple undef test !; ## Note: We silently allow things like this: [[[]],[]] -$dbh->{pg_expand_array} = 0; +sub safe_getarray { + my $ret = eval { + $getarray->execute(); + $getarray->fetchall_arrayref()->[0][0]; + }; + $@ || $ret +} for my $test (split /\n\n/ => $array_tests) { next unless $test =~ /\w/; my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; - } - if ($qexpected !~ /^ERROR/) { - $qexpected = qq{'$qexpected'}; - } + my $perl_input = eval $input; if ($msg =~ s/NEED (\d+):\s*//) { my $ver = $1; @@ -226,86 +222,45 @@ } } - $t="Correct array inserted: $msg : $input"; - $cleararray->execute(); + # INSERT via bind values + $dbh->rollback; eval { - $addarray->execute(eval $input); + $addarray->execute($perl_input); }; if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); + like ($@, qr{$1}, "[bind] Array insert error : $msg : $input"); } else { - is ($@, q{}, "Array worked : $msg : $input"); - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - is ($result, $expected, $t); - } - - $t="Array quote worked : $msg : $input"; - eval { - $result = $dbh->quote(eval $input ); - }; - if ($qexpected =~ /error:\s+(.+)/i) { - my $errmsg = $1; - $errmsg =~ s/bind/quote/; - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); - } - else { - is ($@, q{}, $t); - - $t="Correct array quote: $msg : $input"; - is ($result, $qexpected, $t); - } - -} + is ($@, q{}, "[bind] Array insert success : $msg : $input"); + $t="[bind][!expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 0; + is (safe_getarray, $expected, $t); -## Same thing, but expand the arrays -$dbh->{pg_expand_array} = 1; - -for my $test (split /\n\n/ => $array_tests) { - next unless $test =~ /\w/; - my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; + $t="[bind][expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 1; + is_deeply (safe_getarray, $perl_input, $t); } - if ($msg =~ s/NEED (\d+):\s*//) { - my $ver = $1; - if ($pgversion < $ver) { - SKIP: { - skip ('Cannot test NULL arrays unless version 8.2 or better', 2); - } - next; - } - } - - $t="Array worked : $msg : $input"; - $cleararray->execute(); + # INSERT via `quote' and dynamic SQL + $dbh->rollback; eval { - $addarray->execute(eval $input); + $quotearr = $dbh->quote($perl_input); + $SQL = qq{INSERT INTO dbd_pg_test(id,pname,testarray) VALUES (99,'Array Testing',$quotearr)}; + $dbh->do($SQL); }; if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); + my $errmsg = $1; + $errmsg =~ s/bind/quote/; + like ($@, qr{$errmsg}, "[quote] Array insert error : $msg : $input"); } else { - is ($@, q{}, $t); + is ($@, q{}, "[quote] Array insert success : $msg : $input"); - $t="Correct array inserted: $msg : $input"; - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - $qexpected =~ s/{}/{''}/; - $qexpected =~ y/{}/[]/; - $qexpected =~ s/NULL/undef/g; - if ($msg =~ /closing brace/) { - $qexpected =~ s/]"/}"/; - } - $expected = eval $qexpected; - is_deeply ($result, $expected, $t); + # No need to recheck !expand case. + + $t="[quote][expand] Correct array inserted: $msg : $input"; + is_deeply (safe_getarray, $perl_input, $t); } if ($msg =~ /STOP/) { @@ -315,7 +270,6 @@ $dbh->disconnect; exit; } - }
Subject: Fix marshalling of arrays containing ', ", and/or \ (endorsing Noah's patch)
As discussed on the DBD::Pg mailing list, there was a small bug in my additional test coverage I added. ( I should have used the "testarray" column instead of "testarray2" ). Once that was corrected, Noah's patch passed my additional test coverage as well as own. Based on that, I endorse Noah's match and recommend that it be merged. Here's the thread from the recent mailing list discussion: http://thread.gmane.org/gmane.comp.db.postgresql.dbdpg.general/2740 Mark
Subject: Fix marshalling of arrays containing ', ", and/or \ (patch, v3)
Attached is the revised version of Noah's patch that includes my corrected additional test coverage.
Subject: dbdpg-array-backslash-v3.patch
Mon Oct 10 10:46:33 EDT 2011 Mark Stosberg <mark@summersault.com> * Noah's patch, plus my additional test, with fix for testarray column name diff -rN -u old-DBD-Pg-2.18.1/Pg.xs new-DBD-Pg-2.18.1/Pg.xs --- old-DBD-Pg-2.18.1/Pg.xs 2011-10-10 10:47:52.000000000 -0400 +++ new-DBD-Pg-2.18.1/Pg.xs 2011-10-10 10:47:52.000000000 -0400 @@ -200,15 +200,18 @@ SvGETMAGIC(to_quote_sv); + /* Reject references other than overloaded objects (presumed + stringifiable) and arrays (will make a PostgreSQL array). */ + if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { + if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) + croak("Cannot quote a reference"); + to_quote_sv = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version); + } + /* Null is always returned as "NULL", so we can ignore any type given */ if (!SvOK(to_quote_sv)) { RETVAL = newSVpvn("NULL", 4); } - else if (SvROK(to_quote_sv) && !SvAMAGIC(to_quote_sv)) { - if (SvTYPE(SvRV(to_quote_sv)) != SVt_PVAV) - croak("Cannot quote a reference"); - RETVAL = pg_stringify_array(to_quote_sv, ",", imp_dbh->pg_server_version, 1); - } else { sql_type_info_t *type_info; char *quoted; diff -rN -u old-DBD-Pg-2.18.1/dbdimp.c new-DBD-Pg-2.18.1/dbdimp.c --- old-DBD-Pg-2.18.1/dbdimp.c 2011-10-10 10:47:52.000000000 -0400 +++ new-DBD-Pg-2.18.1/dbdimp.c 2011-10-10 10:47:52.000000000 -0400 @@ -2284,7 +2284,7 @@ } else if (SvTYPE(SvRV(newvalue)) == SVt_PVAV) { SV * quotedval; - quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version, 0); + quotedval = pg_stringify_array(newvalue,",",imp_dbh->pg_server_version); currph->valuelen = sv_len(quotedval); Renew(currph->value, currph->valuelen+1, char); /* freed in dbd_st_destroy */ Copy(SvUTF8(quotedval) ? SvPVutf8_nolen(quotedval) : SvPV_nolen(quotedval), @@ -2420,7 +2420,7 @@ /* ================================================================== */ -SV * pg_stringify_array(SV *input, const char * array_delim, int server_version, int extraquotes) { +SV * pg_stringify_array(SV *input, const char * array_delim, int server_version) { dTHX; AV * toparr; @@ -2439,14 +2439,12 @@ if (TSTART) TRC(DBILOGFP, "%sBegin pg_stringify_array\n", THEADER); toparr = (AV *) SvRV(input); - value = extraquotes ? newSVpv("'{", 2) : newSVpv("{", 1); + value = newSVpv("{", 1); /* Empty arrays are easy */ if (av_len(toparr) < 0) { av_clear(toparr); sv_catpv(value, "}"); - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (empty)\n", THEADER); return value; } @@ -2516,14 +2514,9 @@ SvUTF8_on(value); string = SvPV(svitem, stringlength); while (stringlength--) { - - /* If an embedded quote, throw a backslash before it */ - if ('\"' == *string) + /* Escape backslashes and double-quotes. */ + if ('\"' == *string || '\\' == *string) sv_catpvn(value, "\\", 1); - /* If a backslash, double it up */ - if ('\\' == *string) { - sv_catpvn(value, "\\\\\\", 3); - } sv_catpvn(value, string, 1); string++; } @@ -2548,8 +2541,6 @@ for (xy=0; xy<array_depth; xy++) { sv_catpv(value, "}"); } - if (extraquotes) - sv_catpv(value, "'"); if (TEND) TRC(DBILOGFP, "%sEnd pg_stringify_array (string: %s)\n", THEADER, neatsvpv(value,0)); return value; diff -rN -u old-DBD-Pg-2.18.1/dbdimp.h new-DBD-Pg-2.18.1/dbdimp.h --- old-DBD-Pg-2.18.1/dbdimp.h 2011-10-10 10:47:52.000000000 -0400 +++ new-DBD-Pg-2.18.1/dbdimp.h 2011-10-10 10:47:52.000000000 -0400 @@ -190,7 +190,7 @@ SV * pg_db_pg_notifies (SV *dbh, imp_dbh_t *imp_dbh); -SV * pg_stringify_array(SV * input, const char * array_delim, int server_version, int extraquotes); +SV * pg_stringify_array(SV * input, const char * array_delim, int server_version); int pg_quickexec (SV *dbh, const char *sql, const int asyncflag); diff -rN -u old-DBD-Pg-2.18.1/t/09arrays.t new-DBD-Pg-2.18.1/t/09arrays.t --- old-DBD-Pg-2.18.1/t/09arrays.t 2011-10-10 10:47:52.000000000 -0400 +++ new-DBD-Pg-2.18.1/t/09arrays.t 2011-10-10 10:47:52.000000000 -0400 @@ -18,7 +18,7 @@ if (! $dbh) { plan skip_all => 'Connection to database failed, cannot continue testing'; } -plan tests => 257; +plan tests => 200; isnt ($dbh, undef, 'Connect to database for array testing'); @@ -26,10 +26,6 @@ my $pgversion = $dbh->{pg_server_version}; -if ($pgversion >= 80100) { - $dbh->do('SET escape_string_warning = false'); -} - my $SQL = q{DELETE FROM dbd_pg_test WHERE pname = 'Array Testing'}; my $cleararray = $dbh->prepare($SQL); @@ -52,9 +48,9 @@ my $getarray_bool = $dbh->prepare($SQL); $t='Array quoting allows direct insertion into statements'; -$SQL = q{INSERT INTO dbd_pg_test (id,testarray2) VALUES }; +$SQL = q{INSERT INTO dbd_pg_test (id,testarray) VALUES }; my $quoteid = $dbh->quote(123); -my $quotearr = $dbh->quote([456]); +my $quotearr = $dbh->quote(["Quote's Test"]); $SQL .= qq{($quoteid, $quotearr)}; eval { $dbh->do($SQL); @@ -62,8 +58,8 @@ is ($@, q{}, $t); $dbh->rollback(); -## Input -## Expected +## Input (eval-able Perl) +## Expected (ERROR or raw PostgreSQL output) ## Name of test my $array_tests = @@ -120,51 +116,51 @@ Unbalanced array [123] -{123} quote: {"123"} +{123} Simple 1-D numeric array ['abc'] -{abc} quote: {"abc"} +{abc} Simple 1-D text array ['a','b,c'] -{a,"b,c"} quote: {"a","b,c"} +{a,"b,c"} Text array with commas and quotes ['a','b,}'] -{a,"b,}"} quote: {"a","b,}"} +{a,"b,}"} Text array with commas, escaped closing brace ['a','b,]'] -{a,"b,]"} quote: {"a","b,]"} +{a,"b,]"} Text array with commas, escaped closing bracket [1,2] -{1,2} quote: {"1","2"} +{1,2} Simple 1-D numeric array [[1]] -{{1}} quote: {{"1"}} +{{1}} Simple 2-D numeric array [[1,2]] -{{1,2}} quote: {{"1","2"}} +{{1,2}} Simple 2-D numeric array [[[1]]] -{{{1}}} quote: {{{"1"}}} +{{{1}}} Simple 3-D numeric array [[["alpha",2],[23,"pop"]]] -{{{alpha,2},{23,pop}}} quote: {{{"alpha","2"},{"23","pop"}}} +{{{alpha,2},{23,pop}}} 3-D mixed array [[[1,2,3],[4,5,"6"],["seven","8","9"]]] -{{{1,2,3},{4,5,6},{seven,8,9}}} quote: {{{"1","2","3"},{"4","5","6"},{"seven","8","9"}}} +{{{1,2,3},{4,5,6},{seven,8,9}}} 3-D mixed array [q{O'RLY?}] -{O'RLY?} quote: {"O'RLY?"} +{O'RLY?} Simple single quote [q{O"RLY?}] @@ -172,19 +168,19 @@ Simple double quote [[q{O"RLY?}],[q|'Ya' - "really"|],[123]] -{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} quote: {{"O\"RLY?"},{"'Ya' - \"really\""},{"123"}} +{{"O\"RLY?"},{"'Ya' - \"really\""},{123}} Many quotes ["Single\\\\Backslash"] -{"Single\\\\\\\\Backslash"} quote: {"Single\\\\\\\\Backslash"} +{"Single\\\\Backslash"} Single backslash testing ["Double\\\\\\\\Backslash"] -{"Double\\\\\\\\\\\\\\\\Backslash"} quote: {"Double\\\\\\\\\\\\\\\\Backslash"} +{"Double\\\\\\\\Backslash"} Double backslash testing [["Test\\\nRun","Quite \"so\""],["back\\\\\\\\slashes are a \"pa\\\\in\"",123] ] -{{"Test\\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"",123}} quote: {{"Test\\\\\\\nRun","Quite \"so\""},{"back\\\\\\\\\\\\\\\\slashes are a \"pa\\\\\\\\in\"","123"}} +{{"Test\\\nRun","Quite \"so\""},{"back\\\\\\\\slashes are a \"pa\\\\in\"",123}} Escape party - backslash+newline, two + one [undef] @@ -196,25 +192,25 @@ NEED 80200: Simple undef test [[1,2],[undef,3],["four",undef],[undef,undef]] -{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} quote: {{"1","2"},{NULL,"3"},{"four",NULL},{NULL,NULL}} +{{1,2},{NULL,3},{four,NULL},{NULL,NULL}} NEED 80200: Multiple undef test !; ## Note: We silently allow things like this: [[[]],[]] -$dbh->{pg_expand_array} = 0; +sub safe_getarray { + my $ret = eval { + $getarray->execute(); + $getarray->fetchall_arrayref()->[0][0]; + }; + $@ || $ret +} for my $test (split /\n\n/ => $array_tests) { next unless $test =~ /\w/; my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; - } - if ($qexpected !~ /^ERROR/) { - $qexpected = qq{'$qexpected'}; - } + my $perl_input = eval $input; if ($msg =~ s/NEED (\d+):\s*//) { my $ver = $1; @@ -226,86 +222,45 @@ } } - $t="Correct array inserted: $msg : $input"; - $cleararray->execute(); + # INSERT via bind values + $dbh->rollback; eval { - $addarray->execute(eval $input); + $addarray->execute($perl_input); }; if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); + like ($@, qr{$1}, "[bind] Array insert error : $msg : $input"); } else { - is ($@, q{}, "Array worked : $msg : $input"); - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - is ($result, $expected, $t); - } - - $t="Array quote worked : $msg : $input"; - eval { - $result = $dbh->quote(eval $input ); - }; - if ($qexpected =~ /error:\s+(.+)/i) { - my $errmsg = $1; - $errmsg =~ s/bind/quote/; - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); - like ($@, qr{$errmsg}, "Array quote failed : $msg : $input"); - } - else { - is ($@, q{}, $t); - - $t="Correct array quote: $msg : $input"; - is ($result, $qexpected, $t); - } - -} + is ($@, q{}, "[bind] Array insert success : $msg : $input"); + $t="[bind][!expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 0; + is (safe_getarray, $expected, $t); -## Same thing, but expand the arrays -$dbh->{pg_expand_array} = 1; - -for my $test (split /\n\n/ => $array_tests) { - next unless $test =~ /\w/; - my ($input,$expected,$msg) = split /\n/ => $test; - my $qexpected = $expected; - if ($expected =~ s/\s*quote:\s*(.+)//) { - $qexpected = $1; + $t="[bind][expand] Correct array inserted: $msg : $input"; + $dbh->{pg_expand_array} = 1; + is_deeply (safe_getarray, $perl_input, $t); } - if ($msg =~ s/NEED (\d+):\s*//) { - my $ver = $1; - if ($pgversion < $ver) { - SKIP: { - skip ('Cannot test NULL arrays unless version 8.2 or better', 2); - } - next; - } - } - - $t="Array worked : $msg : $input"; - $cleararray->execute(); + # INSERT via `quote' and dynamic SQL + $dbh->rollback; eval { - $addarray->execute(eval $input); + $quotearr = $dbh->quote($perl_input); + $SQL = qq{INSERT INTO dbd_pg_test(id,pname,testarray) VALUES (99,'Array Testing',$quotearr)}; + $dbh->do($SQL); }; if ($expected =~ /error:\s+(.+)/i) { - like ($@, qr{$1}, "Array failed : $msg : $input"); - like ($@, qr{$1}, "Array failed : $msg : $input"); + my $errmsg = $1; + $errmsg =~ s/bind/quote/; + like ($@, qr{$errmsg}, "[quote] Array insert error : $msg : $input"); } else { - is ($@, q{}, $t); + is ($@, q{}, "[quote] Array insert success : $msg : $input"); - $t="Correct array inserted: $msg : $input"; - $getarray->execute(); - $result = $getarray->fetchall_arrayref()->[0][0]; - $qexpected =~ s/{}/{''}/; - $qexpected =~ y/{}/[]/; - $qexpected =~ s/NULL/undef/g; - if ($msg =~ /closing brace/) { - $qexpected =~ s/]"/}"/; - } - $expected = eval $qexpected; - is_deeply ($result, $expected, $t); + # No need to recheck !expand case. + + $t="[quote][expand] Correct array inserted: $msg : $input"; + is_deeply (safe_getarray, $perl_input, $t); } if ($msg =~ /STOP/) { @@ -315,7 +270,6 @@ $dbh->disconnect; exit; } - }
From: noah [...] leadboat.com
Hi Mark, On Mon Oct 10 10:43:19 2011, MARKSTOS wrote: Show quoted text
> As discussed on the DBD::Pg mailing list, there was a small bug in my > additional test coverage I added. ( I should have used the "testarray" > column instead of "testarray2" ). Once that was corrected, Noah's patch > passed my additional test coverage as well as own. > > Based on that, I endorse Noah's [p]atch and recommend that it be merged.
Thanks for updating the patch and testing; I'm sorry for not having reviewed your feedback earlier. dbdpg-array-backslash-v3.patch adds to Pg.xs two lines having a space followed by a tab. Other than that, it looks good to me. I also agree with your suggestion in [1] concerning the naming of columns like "testarray2". Thanks, nm [1] http://thread.gmane.org/gmane.comp.db.postgresql.dbdpg.general/2744
Subject: Fix marshalling of arrays containing ', ", and/or \ (feedback from maintainers requested)
To the maintainers of DBD::Pg: In this nearly 6-month old ticket we've identified a notable bug with quoting, provided automated test coverage to confirm the issue, and provided a complete patch to address the issue, which passes all the other regression tests plus the new tests. The issue has been independently identified by multiple peoples, and the provided patch has been peer-tested. Could you comment on when this could be merged and released, or what else may become of it?
Subject: Re: [rt.cpan.org #58552] Fix marshalling of arrays containing ', ", and/or \ (feedback from maintainers requested)
Date: Wed, 16 Nov 2011 10:20:31 -0800
To: bug-DBD-Pg [...] rt.cpan.org
From: "David E. Wheeler" <david [...] justatheory.com>
On Nov 16, 2011, at 5:41 AM, MARKSTOS via RT wrote: Show quoted text
> Could you comment on when this could be merged and released, or what else > may become of it?
I’m trying to chase Greg down on IRC. I would commit your patch, but we need to do some branching in the Git repository first. Best, David
Show quoted text
> I’m trying to chase Greg down on IRC. I would commit your patch, but > we need to do some branching in the Git repository first.
Thanks for looking at this, David. This seems like a valuable bug to get addressed. We are moving forward with putting the patch proposed here in production in the meantime. Mark
Subject: Re: [rt.cpan.org #58552] Fix marshalling of arrays containing ', ", and/or \
Date: Thu, 12 Jan 2012 21:15:38 -0800
To: bug-DBD-Pg [...] rt.cpan.org
From: "David E. Wheeler" <david [...] justatheory.com>
On Dec 30, 2011, at 11:05 AM, MARKSTOS via RT wrote: Show quoted text
> Thanks for looking at this, David. This seems like a valuable bug to get > addressed. We are moving forward with putting the patch proposed here in > production in the meantime.
Yeah, it will be done. Doing some nagging now… David
From: noah [...] leadboat.com
Confirmed fix in git master. Thanks, all.