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();