Author: turnstep
Date: Fri Dec 12 08:46:21 2008
New Revision: 12153
Modified:
DBD-Pg/trunk/Changes
DBD-Pg/trunk/dbdimp.c
DBD-Pg/trunk/t/12placeholders.t
Log:
Fix placeholder parsing, per bug 41582
Modified: DBD-Pg/trunk/Changes
==============================================================================
--- DBD-Pg/trunk/Changes (original)
+++ DBD-Pg/trunk/Changes Fri Dec 12 08:46:21 2008
@@ -1,5 +1,9 @@
('GSM' is Greg Sabino Mullane, greg-738XdyZ4GzZWk0Htik3J/[email protected])
+2.11.7
+
+ - Fix placeholder parsing logic (CPAN bug #41582)
+
2.11.6 Released November 30, 2008 (subversion r12126)
- Only set UTF8 flag on array items after UTF8 test. (CPAN bug #41253)
Modified: DBD-Pg/trunk/dbdimp.c
==============================================================================
--- DBD-Pg/trunk/dbdimp.c (original)
+++ DBD-Pg/trunk/dbdimp.c Fri Dec 12 08:46:21 2008
@@ -1500,6 +1500,8 @@
/* Builds the "segment" and "placeholder" structures for a statement handle */
+ D_imp_dbh_from_sth;
+
STRLEN currpos; /* Where we currently are in the statement string */
STRLEN sectionstart, sectionstop; /* Borders of current section */
@@ -1524,6 +1526,8 @@
char * dollarstring = NULL; /* Dynamic string between $$ in dollar quoting */
+ char standard_conforming_strings = 1; /* Status 0=on 1=unknown -1=off */
+
STRLEN xlen; /* Because "x" is too hard to search for */
int xint;
@@ -1602,15 +1606,24 @@
if ('\'' == ch || '"' == ch) {
quote = ch;
backslashes = 0;
+ if ('\'' == ch && 1 == standard_conforming_strings) {
+ const char * scs = PQparameterStatus(imp_dbh->conn,"standard_conforming_strings");
+ standard_conforming_strings = (NULL==scs ? 1 : strncmp(scs,"on",2));
+ }
+
/* Go until ending quote character (unescaped) or end of string */
while (quote && ++currpos && (ch = *statement++)) {
/* 1.1 : single quotes have no meaning in double-quoted sections and vice-versa */
/* 1.2 : backslashed quotes do not end the section */
- if (ch == quote && (0==(backslashes&1))) {
+ /* 1.2.1 : backslashes have no meaning in double quoted sections */
+ /* 1.2.2 : if standard_confirming_strings is set, ignore backslashes in single quotes */
+ if (ch == quote && (quote == '"' || 0==(backslashes&1))) {
quote = 0;
}
- else if ('\\' == ch)
- backslashes++;
+ else if ('\\' == ch) {
+ if (quote == '"' || standard_conforming_strings)
+ backslashes++;
+ }
else
backslashes = 0;
}
@@ -1627,14 +1640,13 @@
/* 2: A comment block: */
if (('-' == ch && '-' == *statement) ||
- ('/' == ch && '/' == *statement) ||
('/' == ch && '*' == *statement)
) {
quote = *statement;
/* Go until end of comment (may be newline) or end of the string */
while (quote && ++currpos && (ch = *statement++)) {
- /* 2.1: dashdash and slashslash only terminate at newline */
- if (('-' == quote || '/' == quote) && '\n' == ch) {
+ /* 2.1: dashdash only terminates at newline */
+ if ('-' == quote && '\n' == ch) {
quote=0;
}
/* 2.2: slashstar ends with a matching starslash */
@@ -1655,8 +1667,16 @@
} /* end comment section */
/* 3: advanced dollar quoting - only if the backend is version 8 or higher */
- if (version >= 80000 && '$' == ch && (*statement == '$' || *statement >= 'A')) {
- /* Unlike PG, we allow a little more latitude in legal characters - anything >= 65 can be used */
+ if (version >= 80000 && '$' == ch &&
+ (*statement == '$'
+ || *statement == '_'
+ || (*statement >= 'A' && *statement <= 'Z')
+ || (*statement >= 'a' && *statement <= 'z'))) {
+ /* "SQL identifiers must begin with a letter (a-z, but also letters with diacritical marks and non-Latin letters)
+ or an underscore (_). Subsequent characters in an identifier or key word can be letters, underscores,
+ digits (0-9), or dollar signs ($)
+ */
+ /* Postgres technically allows \200-\377 as well, but we don't */
sectionsize = 0; /* How far from the first dollar sign are we? */
found = 0; /* Have we found the end of the dollarquote? */
@@ -1664,14 +1684,19 @@
while ((ch = *statement++)) {
sectionsize++;
- /* If we hit an invalid character, bail out */
- if (ch <= 32 || (ch >= '0' && ch <= '9')) {
- break;
- }
if ('$' == ch) {
found = DBDPG_TRUE;
break;
}
+
+ /* If we hit an invalid character, bail out */
+ if (ch <= 47
+ || (ch >= 58 && ch <= 64)
+ || (ch >= 91 && ch <= 94)
+ || ch == 96
+ || (ch >= 123)) {
+ break;
+ }
} /* end first scan */
/* Not found? Move to the next letter after the dollarsign and move on */
Modified: DBD-Pg/trunk/t/12placeholders.t
==============================================================================
--- DBD-Pg/trunk/t/12placeholders.t (original)
+++ DBD-Pg/trunk/t/12placeholders.t Fri Dec 12 08:46:21 2008
@@ -15,7 +15,7 @@
if (! defined $dbh) {
plan skip_all => 'Connection to database failed, cannot continue testing';
}
-plan tests => 28;
+plan tests => 45;
my $t='Connect to database for placeholder testing';
isnt ($dbh, undef, $t);
@@ -232,10 +232,74 @@
};
is ($@, q{}, $t);
-## Begin custom type testing
+$t='Prepare works with placeholders after double slashes';
+eval {
+ $dbh->do(q{CREATE OPERATOR // ( PROCEDURE=bit, LEFTARG=int, RIGHTARG=int )});
+ $sth = $dbh->prepare(q{SELECT ? // ?});
+ $sth->execute(1,2);
+ $sth->finish();
+};
+is ($@, q{}, $t);
+
+$t='Dollar quotes starting with a number are not treated as valid identifiers';
+eval {
+ $sth = $dbh->prepare(q{SELECT $123$ $123$});
+ $sth->execute(1);
+ $sth->finish();
+};
+like ($@, qr{Invalid placeholders}, $t);
+
+$t='Dollar quotes with invalid characters are not parsed as identifiers';
+for my $char (qw!+ / : @ [ `!) {
+ eval {
+ $sth = $dbh->prepare(qq{SELECT \$abc${char}\$ 123 \$abc${char}\$});
+ $sth->execute();
+ $sth->finish();
+ };
+ like ($@, qr{syntax error}, $t);
+}
+
+$t='Dollar quotes with valid characters are parsed as identifiers';
+$dbh->rollback();
+for my $char (qw{0 9 A Z a z}) {
+ eval {
+ $sth = $dbh->prepare(qq{SELECT \$abc${char}\$ 123 \$abc${char}\$});
+ $sth->execute();
+ $sth->finish();
+ };
+ is ($@, q{}, $t);
+}
+
+$t='Backslash quoting inside double quotes is parsed correctly';
+eval {
+ $sth = $dbh->prepare(q{SELECT * FROM "\" WHERE a=?});
+ $sth->execute(1);
+ $sth->finish();
+};
+like ($@, qr{relation ".*" does not exist}, $t);
+$dbh->rollback();
+$t='Backslash quoting inside single quotes is parsed correctly with standard_conforming_strings off';
+eval {
+ $dbh->do(q{SET standard_conforming_strings = 'off'});
+ $sth = $dbh->prepare(q{SELECT '\', ?});
+ $sth->execute();
+ $sth->finish();
+};
+like ($@, qr{unterminated quoted string}, $t);
+$dbh->rollback();
+
+$t='Backslash quoting inside single quotes is parsed correctly with standard_conforming_strings on';
+eval {
+ $dbh->do(q{SET standard_conforming_strings = 'on'});
+ $sth = $dbh->prepare(q{SELECT '\', ?::int});
+ $sth->execute(1);
+ $sth->finish();
+};
+is ($@, q{}, $t);
+## Begin custom type testing
$dbh->rollback();
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.