*** ./doc/src/sgml/libpq.sgml.orig 2010-01-17 07:04:02.000000000 +0100
--- ./doc/src/sgml/libpq.sgml 2010-01-17 07:07:05.000000000 +0100
***************
*** 2926,3032 ****
Escaping Strings for Inclusion in SQL Commands
- PQescapeStringConn
-
-
- PQescapeString
-
-
escaping strings
in libpq
!
! PQescapeStringConn escapes a string for use within an SQL
! command. This is useful when inserting data values as literal constants
! in SQL commands. Certain characters (such as quotes and backslashes) must
! be escaped to prevent them from being interpreted specially by the SQL parser.
! PQescapeStringConn> performs this operation.
!
!
!
! It is especially important to do proper escaping when handling strings that
! were received from an untrustworthy source. Otherwise there is a security
! risk: you are vulnerable to SQL injection> attacks wherein unwanted
! SQL commands are fed to your database.
!
!
!
! Note that it is not necessary nor correct to do escaping when a data
! value is passed as a separate parameter in PQexecParams> or
! its sibling routines.
!
size_t PQescapeStringConn (PGconn *conn,
char *to, const char *from, size_t length,
int *error);
!
!
!
! PQescapeStringConn> writes an escaped version of the
! from> string to the to> buffer, escaping
! special characters so that they cannot cause any harm, and adding a
! terminating zero byte. The single quotes that must surround
! PostgreSQL> string literals are not included in the
! result string; they should be provided in the SQL command that the
! result is inserted into. The parameter from> points to
! the first character of the string that is to be escaped, and the
! length> parameter gives the number of bytes in this
! string. A terminating zero byte is not required, and should not be
! counted in length>. (If a terminating zero byte is found
! before length> bytes are processed,
! PQescapeStringConn> stops at the zero; the behavior is
! thus rather like strncpy>.) to> shall point
! to a buffer that is able to hold at least one more byte than twice
! the value of length>, otherwise the behavior is undefined.
! Behavior is likewise undefined if the to> and
! from> strings overlap.
!
!
! If the error> parameter is not NULL, then
! *error> is set to zero on success, nonzero on error.
! Presently the only possible error conditions involve invalid multibyte
! encoding in the source string. The output string is still generated
! on error, but it can be expected that the server will reject it as
! malformed. On error, a suitable message is stored in the
! conn> object, whether or not error> is NULL.
!
!
! PQescapeStringConn> returns the number of bytes written
! to to>, not including the terminating zero byte.
!
!
!
! size_t PQescapeString (char *to, const char *from, size_t length);
!
!
!
! PQescapeString> is an older, deprecated version of
! PQescapeStringConn>; the difference is that it does
! not take conn> or error> parameters.
! Because of this, it cannot adjust its behavior depending on the
! connection properties (such as character encoding) and therefore
! it might give the wrong results>. Also, it has no way
! to report error conditions.
!
!
! PQescapeString> can be used safely in single-threaded
! client programs that work with only one PostgreSQL>
! connection at a time (in this case it can find out what it needs to
! know behind the scenes>). In other contexts it is a security
! hazard and should be avoided in favor of
! PQescapeStringConn>.
!
!
Escaping Binary Strings for Inclusion in SQL Commands
--- 2926,3088 ----
Escaping Strings for Inclusion in SQL Commands
escaping strings
in libpq
!
!
!
! PQescapeStringConn
!
! PQescapeStringConn
!
!
!
!
! PQescapeStringConn escapes a string for use within an SQL
! command. This is useful when inserting data values as literal constants
! in SQL commands. Certain characters (such as quotes and backslashes) must
! be escaped to prevent them from being interpreted specially by the SQL parser.
! PQescapeStringConn> performs this operation.
!
!
!
! It is especially important to do proper escaping when handling strings that
! were received from an untrustworthy source. Otherwise there is a security
! risk: you are vulnerable to SQL injection> attacks wherein unwanted
! SQL commands are fed to your database.
!
!
!
! Note that it is not necessary nor correct to do escaping when a data
! value is passed as a separate parameter in PQexecParams> or
! its sibling routines.
!
!
size_t PQescapeStringConn (PGconn *conn,
char *to, const char *from, size_t length,
int *error);
!
!
!
! PQescapeStringConn> writes an escaped version of the
! from> string to the to> buffer, escaping
! special characters so that they cannot cause any harm, and adding a
! terminating zero byte. The single quotes that must surround
! PostgreSQL> string literals are not included in the
! result string; they should be provided in the SQL command that the
! result is inserted into. The parameter from> points to
! the first character of the string that is to be escaped, and the
! length> parameter gives the number of bytes in this
! string. A terminating zero byte is not required, and should not be
! counted in length>. (If a terminating zero byte is found
! before length> bytes are processed,
! PQescapeStringConn> stops at the zero; the behavior is
! thus rather like strncpy>.) to> shall point
! to a buffer that is able to hold at least one more byte than twice
! the value of length>, otherwise the behavior is undefined.
! Behavior is likewise undefined if the to> and
! from> strings overlap.
!
!
! If the error> parameter is not NULL, then
! *error> is set to zero on success, nonzero on error.
! Presently the only possible error conditions involve invalid multibyte
! encoding in the source string. The output string is still generated
! on error, but it can be expected that the server will reject it as
! malformed. On error, a suitable message is stored in the
! conn> object, whether or not error> is NULL.
!
!
! PQescapeStringConn> returns the number of bytes written
! to to>, not including the terminating zero byte.
!
!
!
!
!
! PQescapeString
!
! PQescapeString
!
!
!
!
!
! size_t PQescapeString (char *to, const char *from, size_t length);
!
!
!
! PQescapeString> is an older, deprecated version of
! PQescapeStringConn>; the difference is that it does
! not take conn> or error> parameters.
! Because of this, it cannot adjust its behavior depending on the
! connection properties (such as character encoding) and therefore
! it might give the wrong results>. Also, it has no way
! to report error conditions.
!
!
!
! PQescapeString> can be used safely in single-threaded
! client programs that work with only one PostgreSQL>
! connection at a time (in this case it can find out what it needs to
! know behind the scenes>). In other contexts it is a security
! hazard and should be avoided in favor of
! PQescapeStringConn>.
!
!
!
+
+
+ PQescapeIdentConn
+
+ PQescapeIdentConn
+
+
+
+
+
+
+ void PQescapeIdentConn (PGconn *con,
+ char *to, const char *from,
+ int *error);
+
+
+
+
+ PQescapeIdentConn> writes an escaped string of the
+ from> string to the to>. Result is
+ well formed SQL identifier. to> shall point to
+ a buffer that is able to hold three bytes more than twice of
+ length string from>, otherwise the behavior is undefined.
+
+
+
+ If the error> parameter is not NULL, then
+ *error> is set to zero on success, nonzero on error.
+ Presently the only possible error conditions involve invalid multibyte
+ encoding in the source string. The output string is still generated
+ on error, but it can be expected that the server will reject it as
+ malformed. On error, a suitable message is stored in the
+ conn> object, whether or not error> is NULL.
+
+
+
+
+
+
+
Escaping Binary Strings for Inclusion in SQL Commands
*** ./doc/src/sgml/ref/psql-ref.sgml.orig 2010-01-17 07:04:02.000000000 +0100
--- ./doc/src/sgml/ref/psql-ref.sgml 2010-01-17 07:07:05.000000000 +0100
***************
*** 2335,2340 ****
--- 2335,2361 ----
+ psql provides two additional syntax for
+ retrieving the content of variable. This auxilary syntax ensure
+ necessary escaping when we would to use content as sql literal or
+ sql identifier.
+
+ testdb=> \set foo 'hello world'
+ testdb=> \echo :'foo'
+ 'hello world'
+
+ testdb=> \echo :"foo"
+ "hello world"
+
+ testdb=> SELECT :'foo' AS :"foo";
+ hello world
+ -------------
+ hello world
+ (1 row)
+
+
+
+
If you call \set without a second argument, the
variable is set, with an empty string as value. To unset (or delete) a
variable, use the command \unset.
***************
*** 2722,2728 ****
the variable is copied literally, so it can even contain unbalanced
quotes or backslash commands. You must make sure that it makes sense
where you put it. Variable interpolation will not be performed into
! quoted SQL entities.
--- 2743,2755 ----
the variable is copied literally, so it can even contain unbalanced
quotes or backslash commands. You must make sure that it makes sense
where you put it. Variable interpolation will not be performed into
! quoted SQL entities. Identifiers with special chars
! have to be inserted between double quotes. psql
! ensure necessary quoting with additional syntax:
!
! testdb=> \set foo 'my tab'
! testdb=> SELECT * FROM :"foo";
!
***************
*** 2752,2757 ****
--- 2779,2793 ----
at one point you thought it was great that all Unix commands use the
same escape character.)
+
+
+ With alternative syntax for retrieving content of variables external
+ escaping are not necessary:
+
+ testdb=> \set content `cat my_file.txt`
+ testdb=> INSERT INTO my_table VALUES(:'content');
+
+
Since colons can legally appear in SQL commands, the following rule
*** ./src/bin/psql/psqlscan.l.orig 2010-01-17 07:04:02.000000000 +0100
--- ./src/bin/psql/psqlscan.l 2010-01-17 19:31:49.000000000 +0100
***************
*** 47,52 ****
--- 47,53 ----
#include "settings.h"
#include "variables.h"
+ #include "dumputils.h"
/*
* We use a stack of flex buffers to handle substitution of psql variables.
***************
*** 118,123 ****
--- 119,128 ----
char **txtcopy);
static void emit(const char *txt, int len);
static bool is_utf16_surrogate_first(uint32 c);
+ static char *quote_identifier_conn(PGconn *conn, const char *ident);
+
+ static void appendStringIdentConn(PQExpBuffer buf, const char *str, PGconn *conn);
+
#define ECHO emit(yytext, yyleng)
***************
*** 707,712 ****
--- 712,777 ----
}
}
+ :'[A-Za-z0-9_]+' {
+ /*
+ * Possible psql variable substitution
+ * with literal quoting.
+ */
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ if (value)
+ {
+ /* It is a variable, perform substitution */
+ PQExpBufferData buf;
+
+ initPQExpBuffer(&buf);
+ appendStringLiteralConn(&buf, value, pset.db);
+ push_new_buffer(buf.data);
+ termPQExpBuffer(&buf);
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+ }
+
+ :\"[A-Za-z0-9_]+\" {
+ /* Possible psql variable substitution with double quoting */
+ const char *value;
+
+ /* remove dquotes */
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ if (value)
+ {
+ PQExpBufferData buf;
+
+ initPQExpBuffer(&buf);
+ appendStringIdentConn(&buf, value, pset.db);
+ push_new_buffer(buf.data);
+ termPQExpBuffer(&buf);
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+ }
+
+
/*
* Back to backend-compatible rules.
*/
***************
*** 927,932 ****
--- 992,1044 ----
return LEXRES_OK;
}
+ :'[A-Za-z0-9_]*' {
+ /* Possible psql variable substitution */
+ if (option_type == OT_VERBATIM)
+ ECHO;
+ else
+ {
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ /*
+ * The variable value is just emitted without any
+ * further examination. This is consistent with the
+ * pre-8.0 code behavior, if not with the way that
+ * variables are handled outside backslash commands.
+ */
+ if (value)
+ appendStringLiteralConn(output_buf, value, pset.db);
+ }
+
+ *option_quote = ':';
+
+ return LEXRES_OK;
+ }
+
+ :\"[A-Za-z0-9_]*\" {
+ /* Possible psql variable substitution */
+ if (option_type == OT_VERBATIM)
+ ECHO;
+ else
+ {
+ const char *value;
+
+ yytext[yyleng - 1] = '\0';
+ value = GetVariable(pset.vars, yytext + 2);
+
+ if (value)
+ appendStringIdentConn(output_buf, value, pset.db);
+ }
+
+ *option_quote = ':';
+
+ return LEXRES_OK;
+ }
+
+
"|" {
ECHO;
if (option_type == OT_FILEPIPE)
***************
*** 1740,1742 ****
--- 1852,1887 ----
{
return (c >= 0xD800 && c <= 0xDBFF);
}
+
+
+ /*
+ * Convert a string value to an SQL identifier and append it to
+ * the givem buffer.
+ */
+ static void
+ appendStringIdentConn(PQExpBuffer buf, const char *str, PGconn *conn)
+ {
+ char *buffer;
+ size_t length;
+ size_t retlen;
+ int error;
+
+ appendPQExpBufferChar(buf, '\"');
+
+ length = strlen(str);
+ buffer = pg_malloc(2 * length + 1);
+
+ retlen = PQescapeIdentConn(conn, buffer, str, length, &error);
+ if (error)
+ {
+ const char *error_message = PQerrorMessage(pset.db);
+
+ if (strlen(error_message))
+ psql_error("%s", error_message);
+ }
+
+ appendBinaryPQExpBuffer(buf, buffer, retlen);
+ appendPQExpBufferChar(buf, '\"');
+
+ free(buffer);
+ }
*** ./src/interfaces/libpq/exports.txt.orig 2009-03-31 03:41:27.000000000 +0200
--- ./src/interfaces/libpq/exports.txt 2010-01-17 07:07:05.000000000 +0100
***************
*** 153,155 ****
--- 153,156 ----
PQfireResultCreateEvents 151
PQconninfoParse 152
PQinitOpenSSL 153
+ PQescapeIdentConn 154
*** ./src/interfaces/libpq/fe-exec.c.orig 2010-01-17 07:04:02.000000000 +0100
--- ./src/interfaces/libpq/fe-exec.c 2010-01-17 16:03:31.000000000 +0100
***************
*** 3345,3347 ****
--- 3345,3445 ----
*retbuflen = buflen;
return tmpbuf;
}
+
+
+ /*
+ * PQescapeIdentConn - returns valid SQL identifier.
+ *
+ * Replace " by "" and insert strings to pair of double quotes.
+ *
+ * length is the length of the source string. (Note: if a terminating NUL
+ * is encountered sooner, PQescapeString stops short of "length"; the behavior
+ * is thus rather like strncpy.)
+ *
+ * For safety the buffer at "to" must be at least 2*length + 1 bytes long.
+ * A terminating NUL character is added to the output string, whether the
+ * input is NUL-terminated or not.
+ *
+ * Returns the actual length of the output (not counting the terminating NUL).
+ */
+ extern size_t PQescapeIdentConn(PGconn *conn,
+ char *to, const char *from, size_t length,
+ int *error)
+ {
+ const char *source = from;
+ char *target = to;
+ size_t remaining = length;
+
+ if (!conn)
+ {
+ /* force empty-string result */
+ *to = '\0';
+ if (*error)
+ *error = 1;
+ return 0;
+ }
+
+ if (error)
+ *error = 0;
+
+ while (remaining > 0 && *source != '\0')
+ {
+ char c = *source;
+ int len;
+ int i;
+
+ /* Fast path for plain ASCII */
+ if (!IS_HIGHBIT_SET(c))
+ {
+ /* add double quotes if needed */
+ if (c == '"')
+ *target++ = c;
+ /* copy the character */
+ *target++ = c;
+ source++;
+ remaining--;
+ continue;
+ }
+
+ /* Slow path for possible multibyte characters */
+ len = pg_encoding_mblen(conn->client_encoding, source);
+
+ /* Copy the character */
+ for (i = 0; i < len; i++)
+ {
+ if (remaining == 0 || *source == '\0')
+ break;
+ *target++ = *source++;
+ remaining--;
+ }
+
+ /*
+ * If we hit premature end of string (ie, incomplete multibyte
+ * character), try to pad out to the correct length with spaces. We
+ * may not be able to pad completely, but we will always be able to
+ * insert at least one pad space (since we'd not have quoted a
+ * multibyte character). This should be enough to make a string that
+ * the server will error out on.
+ */
+ if (i < len)
+ {
+ if (error)
+ *error = 1;
+
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("incomplete multibyte character\n"));
+ for (; i < len; i++)
+ {
+ if (((size_t) (target - to)) / 2 >= length)
+ break;
+ *target++ = ' ';
+ }
+ break;
+ }
+ }
+
+ /* Write the terminating NUL character. */
+ *target = '\0';
+
+ return target - to;
+ }
*** ./src/interfaces/libpq/libpq-fe.h.orig 2010-01-17 07:04:02.000000000 +0100
--- ./src/interfaces/libpq/libpq-fe.h 2010-01-17 15:34:53.000000000 +0100
***************
*** 471,476 ****
--- 471,479 ----
extern size_t PQescapeStringConn(PGconn *conn,
char *to, const char *from, size_t length,
int *error);
+ extern size_t PQescapeIdentConn(PGconn *conn,
+ char *to, const char *from, size_t length,
+ int *error);
extern unsigned char *PQescapeByteaConn(PGconn *conn,
const unsigned char *from, size_t from_length,
size_t *to_length);