*** ./doc/src/sgml/libpq.sgml.orig 2009-12-02 15:07:25.000000000 +0100 --- ./doc/src/sgml/libpq.sgml 2010-01-05 14:16:17.062921916 +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 2009-12-25 00:36:39.000000000 +0100 --- ./doc/src/sgml/ref/psql-ref.sgml 2010-01-04 10:45:39.350376804 +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-02 17:57:59.000000000 +0100 --- ./src/bin/psql/psqlscan.l 2010-01-05 13:05:38.035047460 +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. *************** *** 707,712 **** --- 708,783 ---- } } + :'[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(output_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) + { + int error; + char *identif; + + identif = pg_malloc(strlen(value) * 2 + 3); + PQescapeIdentConn(pset.db, identif, value, &error); + + if (error) + { + const char *error_message = PQerrorMessage(pset.db); + + if (strlen(error_message)) + psql_error("%s", error_message); + } + + push_new_buffer(identif); + free(identif); + /* 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 **** --- 998,1067 ---- 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) + { + int error; + char *identif; + + identif = pg_malloc(strlen(value) * 2 + 3); + PQescapeIdentConn(pset.db, identif, value, &error); + + if (error) + { + const char *error_message = PQerrorMessage(pset.db); + + if (strlen(error_message)) + psql_error("%s", error_message); + } + + appendPQExpBufferStr(output_buf, identif); + free(identif); + } + } + + *option_quote = ':'; + + return LEXRES_OK; + } + + "|" { ECHO; if (option_type == OT_FILEPIPE) *** ./src/interfaces/libpq/exports.txt.orig 2009-03-31 03:41:27.000000000 +0200 --- ./src/interfaces/libpq/exports.txt 2010-01-04 10:57:06.934376931 +0100 *************** *** 153,155 **** --- 153,156 ---- PQfireResultCreateEvents 151 PQconninfoParse 152 PQinitOpenSSL 153 + PQescapeIdentConn 154 *** ./src/interfaces/libpq/fe-exec.c.orig 2009-08-04 20:05:42.000000000 +0200 --- ./src/interfaces/libpq/fe-exec.c 2010-01-05 12:57:19.548047500 +0100 *************** *** 3,14 **** * fe-exec.c * functions related to sending a query down to the backend * ! * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.205 2009/08/04 18:05:42 tgl Exp $ * *------------------------------------------------------------------------- */ --- 3,14 ---- * fe-exec.c * functions related to sending a query down to the backend * ! * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.206 2010/01/02 16:58:12 momjian Exp $ * *------------------------------------------------------------------------- */ *************** *** 3345,3347 **** --- 3345,3424 ---- *retbuflen = buflen; return tmpbuf; } + + /* + * PQescapeIdentConn - returns valid SQL identifier. + * + * Replace " by "" and insert strings to pair of double quotes. + * + */ + void + PQescapeIdentConn(PGconn *conn, char *to, const char *source, int *error) + { + if (!conn) + { + /* force empty-string result */ + *to = '\0'; + if (*error) + *error = 1; + return; + } + + *to++ = '"'; + + while (*source != '\0') + { + char c = *source; + int len; + int i; + + /* Fast path for plain ASCII */ + if (!IS_HIGHBIT_SET(c)) + { + if (c == '"') + *to++ = c; + *to++ = c; + source++; + 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 (*source == '\0') + break; + *to++ = *source++; + } + + /* + * 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; + if (conn) + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("incomplete multibyte character\n")); + for (; i < len; i++) + *to++ = ' '; + + break; + } + } + + *to++ = '"'; + + /* Write the terminating NUL character. */ + *to = '\0'; + + return; + } *** ./src/interfaces/libpq/libpq-fe.h.orig 2009-06-11 16:49:14.000000000 +0200 --- ./src/interfaces/libpq/libpq-fe.h 2010-01-05 12:57:37.688923153 +0100 *************** *** 4,13 **** * This file contains definitions for structures and * externs for functions used by frontend postgres applications. * ! * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * ! * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.147 2009/06/11 14:49:14 momjian Exp $ * *------------------------------------------------------------------------- */ --- 4,13 ---- * This file contains definitions for structures and * externs for functions used by frontend postgres applications. * ! * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * ! * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.148 2010/01/02 16:58:12 momjian Exp $ * *------------------------------------------------------------------------- */ *************** *** 476,481 **** --- 476,482 ---- size_t *to_length); extern unsigned char *PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen); + extern void PQescapeIdentConn(PGconn *conn, char *to, const char *source, int *error); /* These forms are deprecated! */ extern size_t PQescapeString(char *to, const char *from, size_t length);