Committed by Greg Sabino Mullane <[email protected]>

Subject: [DBD::Pg 2/2] Ensure that number-colon-number is always ignored as a
potential placeholder. Should allow array[1:2] to start working as expected
again.

---
 dbdimp.c           | 34 ++++++++++++++++++++++++++--------
 t/12placeholders.t | 13 +++++++++++--
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/dbdimp.c b/dbdimp.c
index bfc8a44..476eae7 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -1699,6 +1699,8 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
 
        unsigned char ch; /* The current character being checked */
 
+       unsigned char oldch; /* The previous character */
+
        char quote; /* Current quote or comment character: used only in those 
two blocks */
 
        bool found; /* Simple boolean */
@@ -1754,7 +1756,7 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
        /* Start everyone at the start of the string */
        currpos = sectionstart = 0;
 
-       ch = 1;
+       ch = oldch = 1;
 
        while (1) {
 
@@ -1763,6 +1765,9 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
                        break;
                }
 
+               /* Store the old character in case we need to look backwards */
+               oldch = ch;
+
                /* Put the current letter into ch, and advance statement to the 
next character */
                ch = *statement++;
 
@@ -1771,12 +1776,14 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
 
                /* Quick short-circuit for uninteresting characters */
                if (
-                       (ch < 34 && ch != 0) || (ch > 63 && ch != 91) ||
-                       (ch!=34 && ch!=39 &&    /* simple quoting */
-                        ch!=45 && ch!=47 &&    /* comment */
-                        ch!=36 &&              /* dollar quoting or 
placeholder */
-                        ch!=58 && ch!=63 &&    /* placeholder */
-                        ch!=91 &&              /* array slice */
+                       (ch < 34 && ch != 0)
+                       || (ch > 63 && ch != 91) /* > @ABC... but not [ */
+                       || 
+                       (ch!=34 && ch!=39 &&    /* " ' simple quoting */
+                        ch!=45 && ch!=47 &&    /* - / comment */
+                        ch!=36 &&              /* $   dollar quoting or 
placeholder */
+                        ch!=58 && ch!=63 &&    /* : ? placeholder */
+                        ch!=91 &&              /* [   array slice */
                         ch!=0                  /* end of the string (create 
segment) */
                         )
                        ) {
@@ -1982,8 +1989,9 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
                        if ('?' == ch) {
                                placeholder_type = 1;
                        }
-                       /* Colon style, but skip two colons in a row (e.g. 
myval::float) */
+                       /* Colon style */
                        else if (':' == ch && ! imp_sth->nocolons) {
+                               /* Skip two colons in a row (e.g. myval::float) 
*/
                                if (':' == *statement) {
                                        /* Might as well skip _all_ consecutive 
colons */
                                        while(':' == *statement) {
@@ -1992,6 +2000,16 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
                                        }
                                        continue;
                                }
+                               /* Skip number-colon-number */
+                               if (isDIGIT(oldch) && isDIGIT(*statement)) {
+                                       /* Eat until we don't see a number */
+                                       while (isDIGIT(*statement)) {
+                                               ++statement;
+                                               ++currpos;
+                                       }
+                                       continue;
+                               }
+                               /* Only allow colon placeholders if they start 
with alphanum */
                                if (isALNUM(*statement)) {
                                        while(isALNUM(*statement)) {
                                                ++statement;
diff --git a/t/12placeholders.t b/t/12placeholders.t
index 386f02f..c81bd43 100644
--- a/t/12placeholders.t
+++ b/t/12placeholders.t
@@ -17,7 +17,7 @@ my $dbh = connect_database();
 if (! $dbh) {
        plan skip_all => 'Connection to database failed, cannot continue 
testing';
 }
-plan tests => 250;
+plan tests => 251;
 
 my $t='Connect to database for placeholder testing';
 isnt ($dbh, undef, $t);
@@ -555,13 +555,22 @@ like ($@, qr{unbound placeholder}, $t);
 $t=q{Value of placeholder_nocolons defaults to 0};
 is ($dbh->{pg_placeholder_nocolons}, 0, $t);
 
-$t='Without placeholder_nocolons, queries with array slices fail';
+$t='Simple array slices do not get picked up as placeholders';
 $SQL = q{SELECT argh[1:2] FROM dbd_pg_test_geom WHERE id = ?};
 eval {
        $sth = $dbh->prepare($SQL);
        $sth->execute(1);
        $sth->finish();
 };
+is ($@, q{}, $t);
+
+$t='Without placeholder_nocolons, queries with array slices fail';
+$SQL = q{SELECT argh[1 :2] FROM dbd_pg_test_geom WHERE id = ?};
+eval {
+       $sth = $dbh->prepare($SQL);
+       $sth->execute(1);
+       $sth->finish();
+};
 like ($@, qr{Cannot mix placeholder styles}, $t);
 
 $t='Use of statement level placeholder_nocolons allows use of ? placeholders 
while ignoring :';
-- 
1.8.4

Reply via email to