[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.

dbdpg-commits-gENoVmVU/[email protected] Sun, 18 May 2014 15:31:29 +0000
Newsgroups gmane.comp.db.postgresql.dbdpg.cvs
Message-ID <[email protected]>
Committed by Greg Sabino Mullane <greg-O9fzpki4YnJWk0Htik3J/[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