Author: turnstep
Date: Fri Mar 16 07:52:56 2007
New Revision: 9266

Modified:
   DBD-Pg/trunk/Changes
   DBD-Pg/trunk/Pg.pm
   DBD-Pg/trunk/dbdimp.c
   DBD-Pg/trunk/dbdimp.h
   DBD-Pg/trunk/t/02attribs.t
   DBD-Pg/trunk/t/12placeholders.t

Log:
Add pg_placeholder_dollaronly to accomodate geometric operators 
and other unforeseen cases. Fixes CPAN bug #24124


Modified: DBD-Pg/trunk/Changes
==============================================================================
--- DBD-Pg/trunk/Changes        (original)
+++ DBD-Pg/trunk/Changes        Fri Mar 16 07:52:56 2007
@@ -1,6 +1,9 @@
 ('GSM' is Greg Sabino Mullane, [EMAIL PROTECTED])
 
 1.50
+       - Add $dbh->{pg_placeholder_dollaronly} to allow '?' and other symbols 
+         to be used in prepared statements without getting interpreted as 
+         placeholders, i.e. the geometric operator '?#' (CPAN bug #24124) [GSM]
        - Use prepare_cached in last_insert_id function. (CPAN bug #24313)
        - Switch from cvs to subversion. Switch from gborg to perl.org.
        - Fix pg_description join in table_info(). [Max Cohan [EMAIL PROTECTED]

Modified: DBD-Pg/trunk/Pg.pm
==============================================================================
--- DBD-Pg/trunk/Pg.pm  (original)
+++ DBD-Pg/trunk/Pg.pm  Fri Mar 16 07:52:56 2007
@@ -2259,6 +2259,22 @@
 The different types of placeholders cannot be mixed within a statement, but 
you may
 use different ones for each statement handle you have. Again, this is not 
encouraged.
 
+
+If your queries use operators that contain question marks (some of the native 
+Postgres geometric operators for example) you can tell DBD::Pg to ignore any 
+non-dollar sign placeholders by setting the "pg_placeholder_dollaronly" 
+attribute at either the database handle or the statement handle level. 
Examples:
+
+  $dbh->{pg_placeholder_dollaronly} = 1;
+  $sth = $dbh->prepare(q{SELECT * FROM mytable WHERE lseg1 ?# lseg2 AND name = 
$1});
+  $sth->execute('segname');
+
+Alternatively, you can set it at prepare time:
+
+  $sth = $dbh->prepare(q{SELECT * FROM mytable WHERE lseg1 ?-| lseg2 AND name 
= $1},
+    {pg_placeholder_dollaronly = 1});
+  $sth->execute('segname');
+
 =item B<prepare_cached>
 
   $sth = $dbh->prepare_cached($statement, \%attr);

Modified: DBD-Pg/trunk/dbdimp.c
==============================================================================
--- DBD-Pg/trunk/dbdimp.c       (original)
+++ DBD-Pg/trunk/dbdimp.c       Fri Mar 16 07:52:56 2007
@@ -395,6 +395,7 @@
        imp_dbh->pid_number = getpid();
        imp_dbh->prepare_number = 1;
        imp_dbh->prepare_now = DBDPG_FALSE;
+       imp_dbh->dollaronly = DBDPG_FALSE;
        imp_dbh->pg_errorlevel = 1; /* Matches PG default */
        if (imp_dbh->savepoints) {
                av_undef(imp_dbh->savepoints);
@@ -685,6 +686,9 @@
                        imp_dbh->prepare_now = newval ? DBDPG_TRUE : 
DBDPG_FALSE;
                }
        }
+       else if (25==kl && strEQ(key, "pg_placeholder_dollaronly")) {
+         imp_dbh->dollaronly = newval ? DBDPG_TRUE : DBDPG_FALSE;
+       }
        else {
                return 0;
        }
@@ -728,6 +732,8 @@
                retsv = newSViv((IV)imp_dbh->server_prepare);
        } else if (14==kl && strEQ(key, "pg_prepare_now")) {
                retsv = newSViv((IV)imp_dbh->prepare_now);
+       } else if (25==kl && strEQ(key, "pg_placeholder_dollaronly")) {
+               retsv = newSViv((IV)imp_dbh->dollaronly);
        } else if (14==kl && strEQ(key, "pg_lib_version")) {
                retsv = newSViv((IV) PGLIBVERSION );
        } else if (17==kl && strEQ(key, "pg_server_version")) {
@@ -872,10 +878,12 @@
        imp_sth->seg = NULL;
        imp_sth->ph = NULL;
        imp_sth->type_info = NULL;
+       imp_sth->dollaronly = DBDPG_FALSE;
 
        /* We inherit our prepare preferences from the database handle */
        imp_sth->server_prepare = imp_dbh->server_prepare;
        imp_sth->prepare_now = imp_dbh->prepare_now;
+       imp_sth->dollaronly = imp_dbh->dollaronly;
 
        /* Parse and set any attributes passed in */
        if (attribs) {
@@ -893,6 +901,9 @@
                                imp_sth->prepare_now = 0==SvIV(*svp) ? 
DBDPG_FALSE : DBDPG_TRUE;
                        }
                }
+               if ((svp = 
hv_fetch((HV*)SvRV(attribs),"pg_placeholder_dollaronly", 25, 0)) != NULL) {
+                       imp_sth->dollaronly = SvTRUE(*svp) ? DBDPG_TRUE : 
DBDPG_FALSE;
+               }
        }
 
        /* Figure out the first word in the statement */
@@ -1253,12 +1264,8 @@
                /* Figure out if we have a placeholder */
                placeholder_type = 0;
 
-               /* Normal question mark style */
-               if ('?' == ch) {
-                       placeholder_type = 1;
-               }
                /* Dollar sign placeholder style */
-               else if ('$' == ch && isDIGIT(*statement)) {
+               if ('$' == ch && isDIGIT(*statement)) {
                        if ('0' == *statement)
                                croak("Invalid placeholder value");
                        while(isDIGIT(*statement)) {
@@ -1267,22 +1274,28 @@
                        }
                        placeholder_type = 2;
                }
-               /* Colon style, but skip two colons in a row (e.g. 
myval::float) */
-               else if (':' == ch) {
-                       if (':' == *statement) {
-                               /* Might as well skip _all_ consecutive colons 
*/
-                               while(':' == *statement) {
-                                       ++statement;
-                                       ++currpos;
+               else if (! imp_sth->dollaronly) {
+                       /* Question mark style */
+                       if ('?' == ch) {
+                               placeholder_type = 1;
+                       }
+                       /* Colon style, but skip two colons in a row (e.g. 
myval::float) */
+                       else if (':' == ch) {
+                               if (':' == *statement) {
+                                       /* Might as well skip _all_ consecutive 
colons */
+                                       while(':' == *statement) {
+                                               ++statement;
+                                               ++currpos;
+                                       }
+                                       continue;
                                }
-                               continue;
-                       }
-                       if (isALNUM(*statement)) {
-                               while(isALNUM(*statement)) {
-                                       ++statement;
-                                       ++currpos;
+                               if (isALNUM(*statement)) {
+                                       while(isALNUM(*statement)) {
+                                               ++statement;
+                                               ++currpos;
+                                       }
+                                       placeholder_type = 3;
                                }
-                               placeholder_type = 3;
                        }
                }
 
@@ -2538,6 +2551,9 @@
        else if (14==kl && strEQ(key, "pg_prepare_now")) {
                imp_sth->prepare_now = strEQ(value,"0") ? DBDPG_FALSE : 
DBDPG_TRUE;
        }
+       else if (25==kl && strEQ(key, "pg_placeholder_dollaronly")) {
+               imp_sth->dollaronly = SvTRUE(valuesv) ? DBDPG_TRUE : 
DBDPG_FALSE;
+       }
        else if (15==kl && strEQ(key, "pg_prepare_name")) {
                Safefree(imp_sth->prepare_name);
                New(0, imp_sth->prepare_name, vl+1, char); /* freed in 
dbd_st_destroy (and above) */

Modified: DBD-Pg/trunk/dbdimp.h
==============================================================================
--- DBD-Pg/trunk/dbdimp.h       (original)
+++ DBD-Pg/trunk/dbdimp.h       Fri Mar 16 07:52:56 2007
@@ -1,7 +1,7 @@
 /*
        $Id$
        
-       Copyright (c) 2000-2006 PostgreSQL Global Development Group
+       Copyright (c) 2000-2007 PostgreSQL Global Development Group
        Portions Copyright (c) 1997-2000 Edmund Mergl
        Portions Copyright (c) 1994-1997 Tim Bunce
        
@@ -24,6 +24,7 @@
        bool    pg_enable_utf8;    /* should we attempt to make utf8 strings? 
Set by user, default is 0 */
        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 */
 
        int     pg_protocol;       /* value of PQprotocolVersion, usually 0, 2, 
or 3 */
        int     pg_server_version; /* Server version e.g. 80100 */
@@ -95,6 +96,7 @@
        bool   has_binary;       /* does it have one or more binary 
placeholders? */
        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 */
 };
 
 /* Other (non-static) functions we have added to dbdimp.c */

Modified: DBD-Pg/trunk/t/02attribs.t
==============================================================================
--- DBD-Pg/trunk/t/02attribs.t  (original)
+++ DBD-Pg/trunk/t/02attribs.t  Fri Mar 16 07:52:56 2007
@@ -63,6 +63,7 @@
 d pg_prepare_now - tested in 03smethod.t
 d pg_server_prepare - tested in 03smethod.t
 d pg_prepare_now - tested in 03smethod.t
+d pg_placeholder_dollaronly - tested in 12placeholders.t
 
 s NUM_OF_FIELDS, NUM_OF_PARAMS
 s NAME, NAME_lc, NAME_uc, NAME_hash, NAME_lc_hash, NAME_uc_hash

Modified: DBD-Pg/trunk/t/12placeholders.t
==============================================================================
--- DBD-Pg/trunk/t/12placeholders.t     (original)
+++ DBD-Pg/trunk/t/12placeholders.t     Fri Mar 16 07:52:56 2007
@@ -8,7 +8,7 @@
 $|=1;
 
 if (defined $ENV{DBI_DSN}) {
-       plan tests => 20;
+       plan tests => 27;
 } else {
        plan skip_all => 'Cannot run test unless DBI_DSN is defined. See the 
README file';
 }
@@ -142,7 +142,57 @@
   $sth = $dbh->prepare(qq{SET search_path TO ?});
   $sth->execute('public');
 };
-ok( !$@, 'prepare/execute iwth non-DML placeholder works');
+ok( !$@, 'prepare/execute with non-DML placeholder works');
+
+
+## Make sure we can allow geometric and other placeholders
+eval {
+       $sth = $dbh->prepare(qq{SELECT ?- lseg '(1,0),(1,1)'});
+       $sth->execute();
+};
+like ($@, qr{unbound placeholder}, qq{prepare/execute does not allows 
geometric operators});
+
+$dbh->{pg_placeholder_dollaronly} = 1;
+eval {
+       $sth = $dbh->prepare(qq{SELECT ?- lseg '(1,0),(1,1)'});
+       $sth->execute();
+       $sth->finish();
+};
+is ($@, q{}, qq{prepare/execute allows geometric operator ?- when dollaronly 
set});
+
+eval {
+       $sth = $dbh->prepare(qq{SELECT lseg'(1,0),(1,1)' ?# lseg 
'(2,3),(4,5)'});
+       $sth->execute();
+       $sth->finish();
+};
+is ($@, q{}, qq{prepare/execute allows geometric operator ?# when dollaronly 
set});
+
+is ($dbh->{pg_placeholder_dollaronly}, 1, qq{Value of plcaeholder_dollaronly 
can be retrieved});
+
+$dbh->{pg_placeholder_dollaronly} = 0;
+eval {
+       $sth = $dbh->prepare(q{SELECT uno ?: dos ? tres :foo bar $1});
+       $sth->execute();
+       $sth->finish();
+};
+like ($@, qr{mix placeholder}, qq{prepare/execute does not allow use of raw ? 
and :foo forms});
+
+$dbh->{pg_placeholder_dollaronly} = 1;
+eval {
+       $sth = $dbh->prepare(q{SELECT uno ?: dos ? tres :foo bar $1}, 
{pg_placeholder_dollaronly => 1});
+       $sth->{pg_placeholder_dollaronly} = 1;
+       $sth->execute();
+       $sth->finish();
+};
+like ($@, qr{unbound placeholder}, qq{prepare/execute allows use of raw ? and 
:foo forms when dollaronly set});
+
+$dbh->{pg_placeholder_dollaronly} = 0;
+eval {
+       $sth = $dbh->prepare(q{SELECT uno ?: dos ? tres :foo bar $1}, 
{pg_placeholder_dollaronly => 1});
+       $sth->execute();
+       $sth->finish();
+};
+like ($@, qr{unbound placeholder}, qq{pg_placeholder_dollaronly can be called 
as part of prepare()});
 
 $dbh->rollback();
 

Reply via email to