Committed by Graham Ollis <[email protected]>

Implement pg_placeholder_nocolons rt#95173

---
 Pg.pm    | 28 ++++++++++++++++++++++++++++
 dbdimp.c | 35 ++++++++++++++++++++++++++++++++++-
 dbdimp.h |  2 ++
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/Pg.pm b/Pg.pm
index 1dc8971..68e2772 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -1679,6 +1679,7 @@ use 5.008001;
                                pg_pass                        => undef,
                                pg_pid                         => undef,
                                pg_placeholder_dollaronly      => undef,
+                               pg_placeholder_nocolons        => undef,
                                pg_port                        => undef,
                                pg_prepare_now                 => undef,
                                pg_protocol                    => undef,
@@ -1736,6 +1737,7 @@ use 5.008001;
                                pg_cmd_status             => undef,
                                pg_oid_status             => undef,
                                pg_placeholder_dollaronly => undef,
+                               pg_placeholder_nocolons   => undef,
                                pg_prepare_name           => undef,
                                pg_prepare_now            => undef,
                                pg_segments               => undef,
@@ -2604,6 +2606,20 @@ Alternatively, you can set it at prepare time:
     {pg_placeholder_dollaronly => 1});
   $sth->execute('segname');
 
+If your queries use array slices but you still want to use question marks as
+placeholders, you can tell DBD::Pg to ignore just colon placeholders by setting
+the L</pg_placeholder_nocolons> attribute in the same way. Examples:
+
+  $dbh->{pg_placeholder_nocolons} = 1;
+  $sth = $dbh->prepare(q{SELECT array[1:2] FROM mytable WHERE id = ?});
+  $sth->execute(1);
+
+Again, you may set it param time as well:
+
+  $sth = $dbh->prepare(q{SELECT array[1:2] FROM mytable WHERE id = ?}.
+    {pg_placeholder_nocolons => 1});
+  $sth->execute(1);
+
 =head3 B<prepare_cached>
 
   $sth = $dbh->prepare_cached($statement, \%attr);
@@ -3203,6 +3219,12 @@ DBD::Pg specific attribute. Defaults to false. When 
true, question marks inside
 are not treated as L<placeholders|/Placeholders>. Useful for statements that 
contain unquoted question 
 marks, such as geometric operators.
 
+=head3 B<pg_placeholder_nocolons> (boolean)
+
+DBD::Pg specific attribute. Defaults to false. When true, colons inside of 
statements
+are not treated as L<placeholders|/Placeholders>. Useful for statements that 
contain an
+array slice.
+
 =head3 B<pg_enable_utf8> (integer)
 
 DBD::Pg specific attribute. The behavior of DBD::Pg with regards to this flag 
has 
@@ -3870,6 +3892,12 @@ DBD::Pg specific attribute. Defaults to off. When true, 
question marks inside of
 being prepared are not treated as placeholders. Useful for statements that 
contain unquoted question 
 marks, such as geometric operators.
 
+=head3 B<pg_placeholder_nocolons> (boolean)
+
+DBD::Pg specific attribute. Defaults to off. When true, colons inside of 
statements
+are not treated as L<placeholders|/Placeholders>. Useful for statements that 
contain an
+array slice.
+
 =head3 B<pg_async> (integer)
 
 DBD::Pg specific attribute. Indicates the current behavior for asynchronous 
queries. See the section 
diff --git a/dbdimp.c b/dbdimp.c
index e55dd83..bfc8a44 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -236,6 +236,7 @@ int dbd_db_login6 (SV * dbh, imp_dbh_t * imp_dbh, char * 
dbname, char * uid, cha
        imp_dbh->prepare_now       = DBDPG_FALSE;
        imp_dbh->done_begin        = DBDPG_FALSE;
        imp_dbh->dollaronly        = DBDPG_FALSE;
+       imp_dbh->nocolons          = DBDPG_FALSE;
        imp_dbh->expand_array      = DBDPG_TRUE;
        imp_dbh->txn_read_only     = DBDPG_FALSE;
        imp_dbh->pid_number        = getpid();
@@ -791,6 +792,12 @@ SV * dbd_db_FETCH_attrib (SV * dbh, imp_dbh_t * imp_dbh, 
SV * keysv)
                        retsv = newSViv((IV)imp_dbh->switch_prepared);
                break;
 
+       case 23: /* pg_placeholder_nocolons */
+
+               if (strEQ("pg_placeholder_nocolons", key))
+                       retsv = newSViv((IV)imp_dbh->nocolons);
+               break;
+
        case 25: /* pg_placeholder_dollaronly */
 
                if (strEQ("pg_placeholder_dollaronly", key))
@@ -954,6 +961,14 @@ int dbd_db_STORE_attrib (SV * dbh, imp_dbh_t * imp_dbh, SV 
* keysv, SV * valuesv
                }
                break;
 
+       case 23: /* pg_placeholder_nocolons */
+
+               if (strEQ("pg_placeholder_nocolons", key)) {
+                       imp_dbh->nocolons = newval ? DBDPG_TRUE : DBDPG_FALSE;
+                       retval = 1;
+               }
+               break;
+
        case 25: /* pg_placeholder_dollaronly */
 
                if (strEQ("pg_placeholder_dollaronly", key)) {
@@ -1113,6 +1128,12 @@ SV * dbd_st_FETCH_attrib (SV * sth, imp_sth_t * imp_sth, 
SV * keysv)
                        retsv = newSViv((IV)imp_sth->switch_prepared);
                break;
 
+       case 23: /* pg_placeholder_nocolons */
+
+               if (strEQ("pg_placeholder_nocolons", key))
+                       retsv = newSViv((IV)imp_sth->nocolons);
+               break;
+
        case 25: /* pg_placeholder_dollaronly */
 
                if (strEQ("pg_placeholder_dollaronly", key))
@@ -1389,6 +1410,14 @@ int dbd_st_STORE_attrib (SV * sth, imp_sth_t * imp_sth, 
SV * keysv, SV * valuesv
                }
                break;
 
+       case 23: /* pg_placeholder_nocolons */
+
+               if (strEQ("pg_placeholder_nocolons", key)) {
+                       imp_sth->nocolons = SvTRUE(valuesv) ? DBDPG_TRUE : 
DBDPG_FALSE;
+                       retval = 1;
+               }
+               break;
+
        case 25: /* pg_placeholder_dollaronly */
 
                if (strEQ("pg_placeholder_dollaronly", key)) {
@@ -1549,6 +1578,7 @@ int dbd_st_prepare (SV * sth, imp_sth_t * imp_sth, char * 
statement, SV * attrib
        imp_sth->switch_prepared  = imp_dbh->switch_prepared;
        imp_sth->prepare_now      = imp_dbh->prepare_now;
        imp_sth->dollaronly       = imp_dbh->dollaronly;
+       imp_sth->nocolons         = imp_dbh->nocolons;
 
        /* Parse and set any attributes passed in */
        if (attribs) {
@@ -1565,6 +1595,9 @@ int dbd_st_prepare (SV * sth, imp_sth_t * imp_sth, char * 
statement, SV * attrib
                if ((svp = 
hv_fetch((HV*)SvRV(attribs),"pg_placeholder_dollaronly", 25, 0)) != NULL) {
                        imp_sth->dollaronly = SvTRUE(*svp) ? DBDPG_TRUE : 
DBDPG_FALSE;
                }
+               if ((svp = 
hv_fetch((HV*)SvRV(attribs),"pg_placeholder_nocolons", 23, 0)) != NULL) {
+                       imp_sth->nocolons = SvTRUE(*svp) ? DBDPG_TRUE : 
DBDPG_FALSE;
+               }
                if ((svp = hv_fetch((HV*)SvRV(attribs),"pg_async", 8, 0)) != 
NULL) {
                        imp_sth->async_flag = (int)SvIV(*svp);
                }
@@ -1950,7 +1983,7 @@ static void pg_st_split_statement (pTHX_ imp_sth_t * 
imp_sth, int version, char
                                placeholder_type = 1;
                        }
                        /* Colon style, but skip two colons in a row (e.g. 
myval::float) */
-                       else if (':' == ch) {
+                       else if (':' == ch && ! imp_sth->nocolons) {
                                if (':' == *statement) {
                                        /* Might as well skip _all_ consecutive 
colons */
                                        while(':' == *statement) {
diff --git a/dbdimp.h b/dbdimp.h
index 22d55e7..350f1a3 100644
--- a/dbdimp.h
+++ b/dbdimp.h
@@ -36,6 +36,7 @@ struct imp_dbh_st {
        bool    prepare_now;       /* force immediate prepares, even with 
placeholders. Set by user, default is 0 */
        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    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} */
 
@@ -112,6 +113,7 @@ struct imp_sth_st {
        bool   has_default;      /* does it have one or more 'DEFAULT' values? 
*/
        bool   has_current;      /* does it have one or more 'DEFAULT' values? 
*/
        bool   dollaronly;       /* Only use $1 as placeholders, allow all else 
*/
+       bool   nocolons;         /* do not consider :1, :2 ... as valid 
placeholders */
        bool   use_inout;        /* Any placeholders using inout? */
        bool   all_bound;        /* Have all placeholders been bound? */
 };
-- 
1.8.4

Reply via email to