Committed by Greg Sabino Mullane <[email protected]>

Subject: [DBD::Pg 3/6] Per report, fix problem with undefined elements in an 
array being passed as arguments.
Lesson here: av_fetch cannot be trusted, always test it first!
Also added a failing (but now passing) test.

---
 dbdimp.c       |   56 +++++++++++++++++++++++++++++++++++---------------------
 t/03dbmethod.t |   18 ++++++++++++++++--
 2 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/dbdimp.c b/dbdimp.c
index 1931f25..175ed97 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -2463,7 +2463,16 @@ SV * pg_stringify_array(SV *input, const char * 
array_delim, int server_version)
 
        done = 0;
        currarr = lastarr = toparr;
+
+       /* We want to walk through to find out the depth */
        while (!done) {
+
+               /* If we come across a null, we are done */
+               if (! av_exists(currarr, 0)) {
+                       done = 1;
+                       break;
+               }
+
                /* Grab the first item of the current array */
                svitem = *av_fetch(currarr, 0, 0);
 
@@ -2509,30 +2518,35 @@ SV * pg_stringify_array(SV *input, const char * 
array_delim, int server_version)
                        sv_catpv(value, "{");
                }
                for (yz=0; yz < array_items; yz++) {
-                       svitem = *av_fetch(currarr, yz, 0);
-
-                       if (SvROK(svitem))
-                               croak("Arrays must contain only scalars and 
other arrays");
-
-                       if (!SvOK(svitem)) { /* Insert NULL if we can */
-                               /* Only version 8.2 and up can handle NULLs in 
arrays */
-                               if (server_version < 80200)
-                                       croak("Cannot use NULLs in arrays until 
version 8.2");
-                               sv_catpv(value, "NULL"); /* Beware of 
array_nulls config param! */
+                       if (! av_exists(currarr, yz)) {
+                               sv_catpv(value, "NULL");
                        }
                        else {
-                               sv_catpv(value, "\"");
-                               if (SvUTF8(svitem))
-                                       SvUTF8_on(value);
-                               string = SvPV(svitem, stringlength);
-                               while (stringlength--) {
-                                       /* Escape backslashes and 
double-quotes. */
-                                       if ('\"' == *string || '\\' == *string)
-                                               sv_catpvn(value, "\\", 1);
-                                       sv_catpvn(value, string, 1);
-                                       string++;
+                               svitem = *av_fetch(currarr, yz, 0);
+
+                               if (SvROK(svitem))
+                                       croak("Arrays must contain only scalars 
and other arrays");
+
+                               if (!SvOK(svitem)) { /* Insert NULL if we can */
+                                       /* Only version 8.2 and up can handle 
NULLs in arrays */
+                                       if (server_version < 80200)
+                                               croak("Cannot use NULLs in 
arrays until version 8.2");
+                                       sv_catpv(value, "NULL"); /* Beware of 
array_nulls config param! */
+                               }
+                               else {
+                                       sv_catpv(value, "\"");
+                                       if (SvUTF8(svitem))
+                                               SvUTF8_on(value);
+                                       string = SvPV(svitem, stringlength);
+                                       while (stringlength--) {
+                                               /* Escape backslashes and 
double-quotes. */
+                                               if ('\"' == *string || '\\' == 
*string)
+                                                       sv_catpvn(value, "\\", 
1);
+                                               sv_catpvn(value, string, 1);
+                                               string++;
+                                       }
+                                       sv_catpv(value, "\"");
                                }
-                               sv_catpv(value, "\"");
                        }
 
                        if (yz < array_items-1)
diff --git a/t/03dbmethod.t b/t/03dbmethod.t
index 6f35e1b..9bcb2ba 100644
--- a/t/03dbmethod.t
+++ b/t/03dbmethod.t
@@ -26,7 +26,7 @@ my $dbh = connect_database();
 if (! $dbh) {
        plan skip_all => 'Connection to database failed, cannot continue 
testing';
 }
-plan tests => 532;
+plan tests => 534;
 
 isnt ($dbh, undef, 'Connect to database for database handle method testing');
 
@@ -103,12 +103,26 @@ eval {
 };
 like ($@, qr{last_insert_id}, $t);
 
-$t='DB handle method "do()" returns correct count with CREATE AS SELECT';
+$t='DB handle method "do" returns correct count with CREATE AS SELECT';
 $dbh->rollback();
 $result = $dbh->do('CREATE TEMP TABLE foobar AS SELECT * FROM pg_class LIMIT 
3');
 $expected = $pgversion >= 90000 ? 3 : '0E0';
 is ($result, $expected, $t);
 
+$t='DB handle method "do" works properly with passed-in array with undefined 
entries';
+$dbh->rollback();
+$dbh->do('CREATE TEMP TABLE foobar (id INT, p TEXT[])');
+my @aa;
+$aa[2] = 'asasa';
+eval {
+       $dbh->do('INSERT INTO foobar (p) VALUES (?)', undef, \@aa);
+};
+is ($@, q{}, $t);
+
+$SQL = 'SELECT * FROM foobar';
+$result = $dbh->selectall_arrayref($SQL)->[0];
+is_deeply ($result, [undef,[undef,undef,'asasa']], $t);
+
 $t='DB handle method "last_insert_id" works when given a valid sequence and an 
invalid table';
 $dbh->rollback();
 eval {
-- 
1.7.1

Reply via email to