[DBD::Pg] Add a call to $dbh->{pg_placeholder_escapes} = 0 as an emergency measure in case the new backslash escape system breaks something. It is very unlikely to do so - and this will probably be removed entirely after a few versions.

dbdpg-commits-gENoVmVU/[email protected] Fri, 2 Jan 2015 23:58:50 +0000
Newsgroups gmane.comp.db.postgresql.dbdpg.cvs
Message-ID <[email protected]>
Committed by Greg Sabino Mullane <greg-O9fzpki4YnJWk0Htik3J/[email protected]>

Add a call to $dbh->{pg_placeholder_escapes} = 0 as an
emergency measure in case the new backslash escape system breaks something.
It is very unlikely to do so - and this will probably be removed entirely
after a few versions.

---
 Pg.pm              |  1 +
 dbdimp.c           | 21 +++++++++++++++++----
 dbdimp.h           |  1 +
 t/12placeholders.t | 14 ++++++++++++--
 4 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/Pg.pm b/Pg.pm
index 703f882..948db96 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -1584,6 +1584,7 @@ use 5.008001;
                 pg_pid                         => undef,
                 pg_placeholder_dollaronly      => undef,
                 pg_placeholder_nocolons        => undef,
+                pg_placeholder_escapes         => undef,
                 pg_port                        => undef,
                 pg_prepare_now                 => undef,
                 pg_protocol                    => undef,
diff --git a/dbdimp.c b/dbdimp.c
index c90d561..543b7c5 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -237,6 +237,7 @@ int dbd_db_login6 (SV * dbh, imp_dbh_t * imp_dbh, char * dbname, char * uid, cha
 	imp_dbh->done_begin        = DBDPG_FALSE;
 	imp_dbh->dollaronly        = DBDPG_FALSE;
 	imp_dbh->nocolons          = DBDPG_FALSE;
+	imp_dbh->ph_escaped        = DBDPG_TRUE;
 	imp_dbh->expand_array      = DBDPG_TRUE;
 	imp_dbh->txn_read_only     = DBDPG_FALSE;
 	imp_dbh->pid_number        = getpid();
@@ -970,6 +971,14 @@ int dbd_db_STORE_attrib (SV * dbh, imp_dbh_t * imp_dbh, SV * keysv, SV * valuesv
 		}
 		break;
 
+	case 22: /* pg_placeholder_escaped */
+
+		if (strEQ("pg_placeholder_escaped", key)) {
+			imp_dbh->ph_escaped = newval ? DBDPG_TRUE : DBDPG_FALSE;
+			retval = 1;
+		}
+		break;
+
 	case 23: /* pg_placeholder_nocolons */
 
 		if (strEQ("pg_placeholder_nocolons", key)) {
@@ -1979,15 +1988,19 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * imp_sth, int version, char
 			continue;
 		}
 
-		/* If this placeholder is escaped, we rewrite the string to remove the
-		   backslash, and move on as if there is no placeholder */
-		if ('\\' == oldch) {
+		/*
+		  If this placeholder is escaped, we rewrite the string to remove the
+		  backslash, and move on as if there is no placeholder.
+		  The use of $dbh->{pg_placeholder_escaped} = 0 is left as an emergency measure.
+		  It will probably be removed at some point.
+		*/
+		if ('\\' == oldch && imp_dbh->ph_escaped) {
 			/* copy the placeholder-like character but ignore the backslash */
 			unsigned char *p = statement-2;
 			while(*p++) {
 				*(p-1) = *p;
 			}
-			/* We need to adjust these items because we just rewrote statement! */
+			/* We need to adjust these items because we just rewrote 'statement'! */
 			statement--;
 			currpos--;
 			ch = *statement;
diff --git a/dbdimp.h b/dbdimp.h
index 5bddc3a..06af917 100644
--- a/dbdimp.h
+++ b/dbdimp.h
@@ -37,6 +37,7 @@ struct imp_dbh_st {
 	bool    done_begin;        /* have we done a begin? (e.g. are we in a transaction?) */
 	bool    dollaronly;        /* only consider $1, $2 ... as valid placeholders */
 	bool    nocolons;          /* do not consider :1, :2 ... as valid placeholders */
+	bool    ph_escaped;        /* allow backslash to escape placeholders */
 	bool    expand_array;      /* transform arrays from the db into Perl arrays? Default is 1 */
 	bool    txn_read_only;     /* are we in read-only mode? Set with $dbh->{ReadOnly} */
 
diff --git a/t/12placeholders.t b/t/12placeholders.t
index cfd7164..254903d 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 => 253;
+plan tests => 254;
 
 my $t='Connect to database for placeholder testing';
 isnt ($dbh, undef, $t);
@@ -867,7 +867,17 @@ eval {
 is($@, '', $t);
 $sth->finish();
 
-## pg_placeholder_escaping = 1;
+## This is an emergency hatch only. Hopefully will never be used in the wild!
+$dbh->{pg_placeholder_escaped} = 0;
+$t = q{Basic placeholder escaping fails when pg_placeholder_escaped is set to false};
+$SQL = qq{SELECT count(*) FROM dbd_pg_test WHERE pname \\?\\? ?};
+$sth = $dbh->prepare($SQL);
+eval {
+	$count = $sth->execute('foobar');
+};
+like($@, qr{execute}, $t);
+$sth->finish();
+
 
 ## Begin custom type testing
 
-- 
1.8.4