Author: turnstep
Date: Thu May 8 19:14:39 2008
New Revision: 11220
Modified:
DBD-Pg/trunk/.perlcriticrc
DBD-Pg/trunk/Changes
DBD-Pg/trunk/Pg.pm
DBD-Pg/trunk/Pg.xs
DBD-Pg/trunk/dbdimp.c
DBD-Pg/trunk/dbdimp.h
DBD-Pg/trunk/quote.c
DBD-Pg/trunk/t/02attribs.t
DBD-Pg/trunk/t/03dbmethod.t
DBD-Pg/trunk/t/06bytea.t
DBD-Pg/trunk/t/12placeholders.t
DBD-Pg/trunk/t/99_spellcheck.t
Log:
Handle backslashes in quoting by using E'' when possible.
Adjust tests for new E''
Flesh out quote() docs a bit.
Don't track standard_conforming_strings at low-level anymore.
Remove mention of pg_auto_escape parameter.
Modified: DBD-Pg/trunk/.perlcriticrc
==============================================================================
--- DBD-Pg/trunk/.perlcriticrc (original)
+++ DBD-Pg/trunk/.perlcriticrc Thu May 8 19:14:39 2008
@@ -2,7 +2,7 @@
profile-strictness = quiet
[Documentation::PodSpelling]
-stop_words = ActiveKids AutoCommit CachedKids ChildHandles ChopBlanks
CompatMode CursorName DBD DBI Datatype dbdpg ErrCount FetchHashKeyName
HandleError HandleSetErr InactiveDestroy LongReadLen LongTruncOk Mergl Momjian
Mullane NULLABLE OID PgBouncer pgend pglibpq pglogin pgprefix pgquote pgstart
Postgres PostgreSQL PrintError PrintWarn README RaiseError RowCache
RowCacheSize SQL SQLSTATE SSL STDIN STDERR STDOUT Sabino Savepoints
ShowErrorStatement TaintIn TaintOut TraceLevel UTF Username afterwards
arrayrefs attr autocommit backend bitmask cancelled datatype dbd dbh errstr fd
filename getfd getline largeobject len libpq pgbuiltin pgsql runtime savepoint
savepoints schemas sslmode tablename tablespace tablespaces tuple typename
username varchar
+stop_words = ActiveKids AutoCommit CachedKids ChildHandles ChopBlanks
CompatMode CursorName DBD DBI Datatype dbdpg ErrCount FetchHashKeyName
HandleError HandleSetErr InactiveDestroy LongReadLen LongTruncOk Mergl Momjian
Mullane NULLABLE OID PgBouncer pgend pglibpq pglogin pgprefix pgquote pgstart
Postgres PostgreSQL PrintError PrintWarn README RaiseError RowCache
RowCacheSize SQL SQLSTATE SSL STDIN STDERR STDOUT Sabino Savepoints
ShowErrorStatement TaintIn TaintOut TraceLevel UTF Username afterwards
arrayrefs attr autocommit backend bitmask bytea cancelled datatype dbd dbh
errstr fd filename getfd getline largeobject len libpq lseg pgbuiltin pgsql
runtime savepoint savepoints schemas sslmode tablename tablespace tablespaces
tuple typename username varchar
[-Bangs::ProhibitCommentedOutCode]
[-Bangs::ProhibitFlagComments]
Modified: DBD-Pg/trunk/Changes
==============================================================================
--- DBD-Pg/trunk/Changes (original)
+++ DBD-Pg/trunk/Changes Thu May 8 19:14:39 2008
@@ -1,5 +1,12 @@
('GSM' is Greg Sabino Mullane, [EMAIL PROTECTED])
+2.7.0
+
+ - Have $dbh->quote() return E'' when server is >= 8.1
+ and string contains backslashes. Fixes any
+ problems with standard_conforming_strings.
+ (CPAN bug #27538) [GSM]
+
2.6.6 Released May 7, 2008 (subversion r11214)
- Fix minor problem in t/99_spellcheck.t
Modified: DBD-Pg/trunk/Pg.pm
==============================================================================
--- DBD-Pg/trunk/Pg.pm (original)
+++ DBD-Pg/trunk/Pg.pm Thu May 8 19:14:39 2008
@@ -2750,10 +2750,20 @@
$rv = $dbh->quote($value, $data_type);
-This module implements its own C<quote> method. In addition to the DBI method
it
-also doubles the backslash, because PostgreSQL treats a backslash as an escape
-character. You may also quote arrayrefs and received a string suitable for
-passing into Postgres array columns.
+This module implements its own C<quote> method. For simple string types, both
backslashes
+and single quotes are doubled. You may also quote arrayrefs and receive a
string
+suitable for passing into Postgres array columns.
+
+If the value contains backslashes, and the server is version 8.1 or higher,
+then the escaped string syntax will be used (which places a capital E before
+the first single quote). This syntax is always used when quoting bytea values
+on servers 8.1 and higher.
+
+The C<data_type> argument is optional and should be one of the type constants
+exported by DBD::Pg (such as PG_BYTEA). In addition to string, bytea, char,
bool,
+and other standard types, the following geometric types are supported: point,
line,
+lseg, box, path, polygon, and circle (PG_POINT, PG_LINE, PG_LSEG, PG_BOX,
+PG_POLYGON, and PG_CIRCLE).
B<NOTE:> The undocumented (and invalid) support for the C<SQL_BINARY> data
type is officially deprecated. Use C<PG_BYTEA> with C<bind_param()> instead:
@@ -2830,18 +2840,6 @@
Supported by this driver as proposed by DBI.
-=item B<pg_auto_escape> (boolean)
-
-PostgreSQL specific attribute. If true, then quotes and backslashes in all
-parameters will be escaped in the following way:
-
- escape quote with a quote (SQL)
- escape backslash with a backslash
-
-The default is on. Note that PostgreSQL also accepts quotes that are
-escaped by a backslash. Any other ASCII character can be used directly in a
-string constant.
-
=item B<pg_enable_utf8> (boolean)
PostgreSQL specific attribute. If true, then the C<utf8> flag will be turned
Modified: DBD-Pg/trunk/Pg.xs
==============================================================================
--- DBD-Pg/trunk/Pg.xs (original)
+++ DBD-Pg/trunk/Pg.xs Thu May 8 19:14:39 2008
@@ -248,7 +248,7 @@
to_quote = SvPV(to_quote_sv, len);
/* Need good debugging here */
- quoted = type_info->quote(to_quote, len, &retlen, 0);
+ quoted = type_info->quote(to_quote, len, &retlen,
imp_dbh->pg_server_version >= 80100 ? 1 : 0);
RETVAL = newSVpvn(quoted, retlen);
if (SvUTF8(to_quote_sv)) /* What about overloaded
objects? */
SvUTF8_on(RETVAL);
Modified: DBD-Pg/trunk/dbdimp.c
==============================================================================
--- DBD-Pg/trunk/dbdimp.c (original)
+++ DBD-Pg/trunk/dbdimp.c Thu May 8 19:14:39 2008
@@ -216,16 +216,6 @@
}
}
- /* Check the status of standard_conforming_strings */
- imp_dbh->standard_escape = DBDPG_FALSE;
- if (imp_dbh->pg_server_version >= 80100) { /* cannot be true until 8.1
*/
- TRACE_PQPARAMETERSTATUS;
- if (NULL != PQparameterStatus(imp_dbh->conn,
"standard_conforming_strings")
- && 0==strncmp("on", PQparameterStatus(imp_dbh->conn,
"standard_conforming_strings"), 2)) {
- imp_dbh->standard_escape = DBDPG_TRUE;
- }
- }
-
imp_dbh->pg_bool_tf = DBDPG_FALSE;
imp_dbh->pg_enable_utf8 = DBDPG_FALSE;
imp_dbh->prepare_now = DBDPG_FALSE;
@@ -2825,8 +2815,12 @@
else {
if (currph->quoted)
Safefree(currph->quoted);
- currph->quoted = currph->bind_type->quote
- (currph->value, currph->valuelen,
&currph->quotedlen, 0); /* freed in dbd_st_destroy */
+ currph->quoted = currph->bind_type->quote(
+ currph->value,
+ currph->valuelen,
+ &currph->quotedlen,
+ imp_dbh->pg_server_version >= 80100 ? 1
: 0
+
); /* freed in dbd_st_destroy */
}
}
/* Set the size of each actual in-place placeholder */
Modified: DBD-Pg/trunk/dbdimp.h
==============================================================================
--- DBD-Pg/trunk/dbdimp.h (original)
+++ DBD-Pg/trunk/dbdimp.h Thu May 8 19:14:39 2008
@@ -24,7 +24,6 @@
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 expand_array; /* Transform arrays from the db into Perl
arrays? Default is 1 */
- bool standard_escape; /* Is standard_conforming_strings turned on?
*/
int pg_protocol; /* value of PQprotocolVersion, usually 3
(could also be 0) */
int pg_server_version; /* Server version e.g. 80100 */
Modified: DBD-Pg/trunk/quote.c
==============================================================================
--- DBD-Pg/trunk/quote.c (original)
+++ DBD-Pg/trunk/quote.c Thu May 8 19:14:39 2008
@@ -11,6 +11,12 @@
#include "Pg.h"
+/*
+The 'estring' indicates if the server is capable of using the E'' syntax
+In other words, is it 8.1 or better?
+It must arrive as 0 or 1
+*/
+
char * null_quote(const char *string, STRLEN len, STRLEN *retlen, int estring)
{
dTHX;
@@ -31,24 +37,28 @@
STRLEN oldlen = len;
const char * const tmp = string;
- (*retlen) = estring ? 3 : 2;
+ (*retlen) = 2;
while (len > 0 && *string != '\0') {
- if (*string == '\'' || *string == '\\') {
+ if (*string == '\'')
+ (*retlen)++;
+ else if (*string == '\\') {
+ if (estring == 1)
+ estring = 2;
(*retlen)++;
}
(*retlen)++;
string++;
len--;
}
+ if (estring == 2)
+ (*retlen)++;
+
string = tmp;
New(0, result, 1+(*retlen), char);
- if (estring) {
+ if (estring == 2)
*result++ = 'E';
- *result++ = '\'';
- }
- else {
- *result++ = '\'';
- }
+ *result++ = '\'';
+
len = oldlen;
while (len > 0 && *string != '\0') {
if (*string == '\'' || *string == '\\') {
@@ -71,7 +81,7 @@
len = 0; /* stops compiler warnings. Remove entirely someday */
tmp = string;
- (*retlen) = estring ? 3 : 2;
+ (*retlen) = 2;
while (*string != '\0') {
if (*string !=9 && *string != 32 && *string != '(' && *string
!= ')'
&& *string != ',' && (*string < '0' || *string > '9'))
@@ -81,13 +91,8 @@
}
string = tmp;
New(0, result, 1+(*retlen), char);
- if (estring) {
- *result++ = 'E';
- *result++ = '\'';
- }
- else {
- *result++ = '\'';
- }
+ *result++ = '\'';
+
while (*string != '\0') {
*result++ = *string++;
}
@@ -103,7 +108,7 @@
const char * const tmp = string;
len = 0; /* stops compiler warnings. Remove entirely someday */
- (*retlen) = estring ? 3 : 2;
+ (*retlen) = 2;
while (*string != '\0') {
if (*string !=9 && *string != 32 && *string != '(' && *string
!= ')'
&& *string != ',' && *string != '[' && *string != ']'
@@ -114,13 +119,8 @@
}
string = tmp;
New(0, result, 1+(*retlen), char);
- if (estring) {
- *result++ = 'E';
- *result++ = '\'';
- }
- else {
- *result++ = '\'';
- }
+ *result++ = '\'';
+
while (*string != '\0') {
*result++ = *string++;
}
@@ -136,7 +136,7 @@
const char * const tmp = string;
len = 0; /* stops compiler warnings. Remove entirely someday */
- (*retlen) = estring ? 3 : 2;
+ (*retlen) = 2;
while (*string != '\0') {
if (*string !=9 && *string != 32 && *string != '(' && *string
!= ')'
&& *string != ',' && *string != '<' && *string != '>'
@@ -147,13 +147,8 @@
}
string = tmp;
New(0, result, 1+(*retlen), char);
- if (estring) {
- *result++ = 'E';
- *result++ = '\'';
- }
- else {
- *result++ = '\'';
- }
+ *result++ = '\'';
+
while (*string != '\0') {
*result++ = *string++;
}
@@ -169,8 +164,9 @@
char * result;
STRLEN oldlen = len;
+ /* For this one, always use the E'' format if we can */
result = string;
- (*retlen) = estring ? 3 : 2;
+ (*retlen) = 2;
while (len > 0) {
if (*string == '\'') {
(*retlen) += 2;
@@ -188,14 +184,14 @@
len--;
}
string = result;
+ if (estring)
+ (*retlen)++;
+
New(0, result, 1+(*retlen), char);
- if (estring) {
+ if (estring)
*result++ = 'E';
- *result++ = '\'';
- }
- else {
- *result++ = '\'';
- }
+ *result++ = '\'';
+
len = oldlen;
while (len > 0) {
if (*string == '\'') { /* Single quote becomes double quotes */
Modified: DBD-Pg/trunk/t/02attribs.t
==============================================================================
--- DBD-Pg/trunk/t/02attribs.t (original)
+++ DBD-Pg/trunk/t/02attribs.t Thu May 8 19:14:39 2008
@@ -16,10 +16,12 @@
if (! defined $dbh) {
plan skip_all => 'Connection to database failed, cannot continue
testing';
}
-plan tests => 131;
+plan tests => 137;
isnt( $dbh, undef, 'Connect to database for handle attributes testing');
+my ($pglibversion,$pgversion) =
($dbh->{pg_lib_version},$dbh->{pg_server_version});
+
my $attributes_tested = q{
d = database handle specific
@@ -320,6 +322,32 @@
$result = $dbh->{pg_pid};
like( $result, qr/^\d+$/, q{DB handle attribute "pg_pid" returns a value});
+SKIP: {
+
+ skip 'Cannot test standard_conforming_strings on pre 8.1 servers', 5;
+
+ $t=q{DB handle attribute "pg_standard_conforming_strings" returns a
valid value};
+ my $oldscs = $dbh->{pg_standard_conforming_strings};
+ like( $oldscs, qr/^on|off$/, $t);
+
+ $dbh->do('SET standard_conforming_strings = on');
+ $t=q{DB handle attribute "pg_standard_conforming_strings" returns
correct value};
+ $result = $dbh->{pg_standard_conforming_strings};
+ is( $result, 'on', $t);
+ $t=q{DB handle attribute "pg_scs" returns correct value};
+ $result = $dbh->{pg_scs};
+ is( $result, 'on', $t);
+
+ $dbh->do('SET standard_conforming_strings = off');
+ $t=q{DB handle attribute "pg_standard_conforming_strings" returns
correct value};
+ $result = $dbh->{pg_standard_conforming_strings};
+ is( $result, 'off', $t);
+ $t=q{DB handle attribute "pg_scs" returns correct value};
+ $result = $dbh->{pg_scs};
+ is( $result, 'off', $t);
+ $dbh->do("SET standard_conforming_strings = $oldscs");
+}
+
## If Encode is available, we will insert some non-ASCII into the test table
## Since this will fail with client encodings such as BIG5, we force UTF8
my $old_encoding = $dbh->selectall_arrayref('SHOW client_encoding')->[0][0];
@@ -336,7 +364,7 @@
$sth->execute(1);
local $dbh->{pg_enable_utf8} = 1;
my $utf8_str = chr(0x100).'dam'; # LATIN CAPITAL LETTER A WITH MACRON
-
+ is( $dbh->quote( $utf8_str ), "'$utf8_str'", $t);
$SQL = "INSERT INTO dbd_pg_test (id, pname, val) VALUES (40,
'$utf8_str', 'Orange')";
is( $dbh->do($SQL), '1', 'Able to insert unicode character into the
database');
$sth->execute(40);
Modified: DBD-Pg/trunk/t/03dbmethod.t
==============================================================================
--- DBD-Pg/trunk/t/03dbmethod.t (original)
+++ DBD-Pg/trunk/t/03dbmethod.t Thu May 8 19:14:39 2008
@@ -25,7 +25,7 @@
if (! defined $dbh) {
plan skip_all => 'Connection to database failed, cannot continue
testing';
}
-plan tests => 220;
+plan tests => 222;
isnt( $dbh, undef, 'Connect to database for database handle method testing');
@@ -999,6 +999,14 @@
}
is( $dbh->quote(1, 4), 1, 'DB handle method "quote" works with a supplied data
type argument');
+## Various backslash tests
+my $E = $pgversion >= 80100 ? q{E} : q{};
+$t=q{DB handle method "quote" works properly with backslashes};
+is( $dbh->quote('foo\\bar'), qq{${E}'foo\\\\bar'}, $t);
+
+$t=q{DB handle method "quote" works properly without backslashes};
+is( $dbh->quote('foobar'), q{'foobar'}, $t);
+
#
# Test various quote types
#
Modified: DBD-Pg/trunk/t/06bytea.t
==============================================================================
--- DBD-Pg/trunk/t/06bytea.t (original)
+++ DBD-Pg/trunk/t/06bytea.t Thu May 8 19:14:39 2008
@@ -46,7 +46,8 @@
my $string = "abc\123\\def\0ghi";
my $result = $dbh->quote($string, { pg_type => PG_BYTEA });
-my $expected = qq{'abc\123\\\\\\\\def\\\\000ghi'};
+my $E = $pgversion >= 80100 ? q{E} : q{};
+my $expected = qq{${E}'abc\123\\\\\\\\def\\\\000ghi'};
is( $result, $expected, 'quote properly handles bytea strings.');
$sth->finish();
Modified: DBD-Pg/trunk/t/12placeholders.t
==============================================================================
--- DBD-Pg/trunk/t/12placeholders.t (original)
+++ DBD-Pg/trunk/t/12placeholders.t Thu May 8 19:14:39 2008
@@ -25,9 +25,10 @@
}
# Make sure that quoting works properly.
+my $E = $pgversion >= 80100 ? q{E} : q{};
$t=q{Quoting works properly};
my $quo = $dbh->quote('\\\'?:');
-is( $quo, q{'\\\\''?:'}, $t);
+is( $quo, qq{${E}'\\\\''?:'}, $t);
$t=q{Quoting works with a function call};
# Make sure that quoting works with a function call.
@@ -134,7 +135,9 @@
my $backslash = $dbh->selectall_arrayref($SQL)->[0][0];
$t=q{Prepare with backslashes inside quotes works};
-$sth = $dbh->prepare(q{SELECT '\\'?'});
+my $scs = $dbh->{pg_scs};
+$SQL = $scs ? q{SELECT E'\\'?'} : q{SELECT '\\'?'};
+$sth = $dbh->prepare($SQL);
eval {
$sth->execute();
};
Modified: DBD-Pg/trunk/t/99_spellcheck.t
==============================================================================
--- DBD-Pg/trunk/t/99_spellcheck.t (original)
+++ DBD-Pg/trunk/t/99_spellcheck.t Thu May 8 19:14:39 2008
@@ -593,6 +593,7 @@
qw
## Pg.pm:
+lseg
afterwards
## Pg.xs:
@@ -670,6 +671,7 @@
ph
## quote.c:
+estring
SVs
compat