Index: doc/TODO =================================================================== RCS file: /projects/cvsroot/pgsql/doc/TODO,v retrieving revision 1.1696 diff -c -r1.1696 TODO *** doc/TODO 27 Oct 2005 14:16:02 -0000 1.1696 --- doc/TODO 25 Jan 2006 22:22:56 -0000 *************** *** 391,397 **** * Allow EXPLAIN to identify tables that were skipped because of constraint_exclusion * Allow EXPLAIN output to be more easily processed by scripts - * Eventually enable escape_string_warning and standard_conforming_strings * Simplify dropping roles that have objects in several databases --- 391,396 ---- Index: doc/src/sgml/config.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/config.sgml,v retrieving revision 1.36 diff -c -r1.36 config.sgml *** doc/src/sgml/config.sgml 4 Nov 2005 23:53:18 -0000 1.36 --- doc/src/sgml/config.sgml 25 Jan 2006 22:22:57 -0000 *************** *** 3728,3737 **** Escape string syntax (E'...') should be used for ! escapes, because in future versions of ! PostgreSQL ordinary strings will have the standard-conforming behavior of treating backslashes ! literally. --- 3728,3755 ---- Escape string syntax (E'...') should be used for ! backslash escape sequences, because ordinary strings have the standard-conforming behavior of treating backslashes ! literally when the standard-conforming-strings ! option is set on. ! ! ! ! ! ! standard_conforming_strings (boolean) ! stringsescape ! ! standard_conforming_strings configuration parameter ! ! ! ! Controls whether ordinary string literals ! ('...') treat backslashes literally, as specified in ! the SQL standard. Applications may check this ! parameter to determine how string literals will be processed. ! The presence of this parameter can also be taken as an indication ! that the escape string syntax (E'...') is supported. *************** *** 3944,3971 **** - - standard_conforming_strings (boolean) - stringsescape - - standard_conforming_strings configuration parameter - - - - Reports whether ordinary string literals - ('...') treat backslashes literally, as specified in - the SQL standard. The value is currently always off, - indicating that backslashes are treated as escapes. It is planned - that this will change to on in a future - PostgreSQL release when string literal - syntax changes to meet the standard. Applications may check this - parameter to determine how string literals will be processed. - The presence of this parameter can also be taken as an indication - that the escape string syntax (E'...') is supported. - - - - --- 3962,3967 ---- Index: src/backend/parser/scan.l =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/scan.l,v retrieving revision 1.128 diff -c -r1.128 scan.l *** src/backend/parser/scan.l 16 Aug 2005 00:48:12 -0000 1.128 --- src/backend/parser/scan.l 25 Jan 2006 22:22:57 -0000 *************** *** 51,63 **** static char *dolqstart; /* current $foo$ quote start string */ /* ! * GUC variable. This is a DIRECT violation of the warning given at the * head of gram.y, ie flex/bison code must not depend on any GUC variables; * as such, changing its value can induce very unintuitive behavior. * But we shall have to live with it as a short-term thing until the switch * to SQL-standard string syntax is complete. */ bool escape_string_warning; static bool warn_on_first_escape; --- 51,64 ---- static char *dolqstart; /* current $foo$ quote start string */ /* ! * GUC variables. This is a DIRECT violation of the warning given at the * head of gram.y, ie flex/bison code must not depend on any GUC variables; * as such, changing its value can induce very unintuitive behavior. * But we shall have to live with it as a short-term thing until the switch * to SQL-standard string syntax is complete. */ bool escape_string_warning; + bool standard_conforming_strings; static bool warn_on_first_escape; *************** *** 77,82 **** --- 78,84 ---- static char *litbufdup(void); static int pg_err_position(void); static void check_escape_warning(void); + static void check_string_escape_warning(unsigned char ychar); /* * When we parse a token that requires multiple lexer rules to process, *************** *** 119,125 **** * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string ! * quoted strings * $foo$ quoted strings */ --- 121,128 ---- * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string ! * standard quoted strings ! * extended quoted strings (support backslash escape sequences) * $foo$ quoted strings */ *************** *** 127,132 **** --- 130,136 ---- %x xc %x xd %x xh + %x xe %x xq %x xdolq *************** *** 200,205 **** --- 204,213 ---- /* Quoted string that allows backslash escapes */ xestart [eE]{quote} + xeinside [^\\']+ + xeescape [\\][^0-7] + xeoctesc [\\][0-7]{1,3} + xehexesc [\\]x[0-9A-Fa-f]{1,2} /* Extended quote * xqdouble implements embedded quote, '''' *************** *** 207,215 **** xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqescape [\\][^0-7] ! xqoctesc [\\][0-7]{1,3} ! xqhexesc [\\]x[0-9A-Fa-f]{1,2} /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string --- 215,221 ---- xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqbackslash [\\] /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string *************** *** 428,500 **** {xqstart} { warn_on_first_escape = true; token_start = yytext; ! BEGIN(xq); startlit(); } {xestart} { warn_on_first_escape = false; token_start = yytext; ! BEGIN(xq); startlit(); } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(INITIAL); yylval.str = litbufdup(); return SCONST; } ! {xqdouble} { addlitchar('\''); } {xqinside} { addlit(yytext, yyleng); } ! {xqescape} { ! if (yytext[1] == '\'') ! { ! if (warn_on_first_escape && escape_string_warning) ! ereport(WARNING, ! (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER), ! errmsg("nonstandard use of \\' in a string literal"), ! errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."), ! errposition(pg_err_position()))); ! warn_on_first_escape = false; /* warn only once per string */ ! } ! else if (yytext[1] == '\\') ! { ! if (warn_on_first_escape && escape_string_warning) ! ereport(WARNING, ! (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER), ! errmsg("nonstandard use of \\\\ in a string literal"), ! errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."), ! errposition(pg_err_position()))); ! warn_on_first_escape = false; /* warn only once per string */ ! } ! else ! check_escape_warning(); addlitchar(unescape_single_char(yytext[1])); } ! {xqoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8); check_escape_warning(); addlitchar(c); } ! {xqhexesc} { unsigned char c = strtoul(yytext+2, NULL, 16); check_escape_warning(); addlitchar(c); } ! {quotecontinue} { /* ignore */ } ! . { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } ! <> { yyerror("unterminated quoted string"); } {dolqdelim} { token_start = yytext; --- 434,495 ---- {xqstart} { warn_on_first_escape = true; token_start = yytext; ! if (standard_conforming_strings) ! BEGIN(xq); ! else ! BEGIN(xe); startlit(); } {xestart} { warn_on_first_escape = false; token_start = yytext; ! BEGIN(xe); startlit(); } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(INITIAL); yylval.str = litbufdup(); return SCONST; } ! {xqdouble} { addlitchar('\''); } {xqinside} { addlit(yytext, yyleng); } ! {xeinside} { ! addlit(yytext, yyleng); ! } ! {xqbackslash} { ! check_string_escape_warning(yytext[1]); ! addlitchar('\\'); ! } ! {xeescape} { ! check_string_escape_warning(yytext[1]); addlitchar(unescape_single_char(yytext[1])); } ! {xeoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8); check_escape_warning(); addlitchar(c); } ! {xehexesc} { unsigned char c = strtoul(yytext+2, NULL, 16); check_escape_warning(); addlitchar(c); } ! {quotecontinue} { /* ignore */ } ! . { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } ! <> { yyerror("unterminated quoted string"); } {dolqdelim} { token_start = yytext; *************** *** 876,881 **** --- 871,903 ---- } static void + check_string_escape_warning(unsigned char ychar) + { + if (ychar == '\'') + { + if (warn_on_first_escape && escape_string_warning) + ereport(WARNING, + (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER), + errmsg("nonstandard use of \\' in a string literal"), + errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."), + errposition(pg_err_position()))); + warn_on_first_escape = false; /* warn only once per string */ + } + else if (ychar == '\\') + { + if (warn_on_first_escape && escape_string_warning) + ereport(WARNING, + (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER), + errmsg("nonstandard use of \\\\ in a string literal"), + errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."), + errposition(pg_err_position()))); + warn_on_first_escape = false; /* warn only once per string */ + } + else + check_escape_warning(); + } + + static void check_escape_warning(void) { if (warn_on_first_escape && escape_string_warning) Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.299.2.1 diff -c -r1.299.2.1 guc.c *** src/backend/utils/misc/guc.c 22 Nov 2005 18:23:24 -0000 1.299.2.1 --- src/backend/utils/misc/guc.c 25 Jan 2006 22:22:58 -0000 *************** *** 219,225 **** static int max_identifier_length; static int block_size; static bool integer_datetimes; - static bool standard_conforming_strings; /* should be static, but commands/variable.c needs to get at these */ char *role_string; --- 219,224 ---- *************** *** 958,967 **** }, { ! {"standard_conforming_strings", PGC_INTERNAL, PRESET_OPTIONS, gettext_noop("'...' strings treat backslashes literally."), ! NULL, ! GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &standard_conforming_strings, false, NULL, NULL --- 957,965 ---- }, { ! {"standard_conforming_strings", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, gettext_noop("'...' strings treat backslashes literally."), ! NULL }, &standard_conforming_strings, false, NULL, NULL Index: src/backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.168.2.2 diff -c -r1.168.2.2 postgresql.conf.sample *** src/backend/utils/misc/postgresql.conf.sample 10 Nov 2005 14:02:59 -0000 1.168.2.2 --- src/backend/utils/misc/postgresql.conf.sample 25 Jan 2006 22:22:58 -0000 *************** *** 416,422 **** #regex_flavor = advanced # advanced, extended, or basic #sql_inheritance = on #default_with_oids = off ! #escape_string_warning = off # - Other Platforms & Clients - --- 416,423 ---- #regex_flavor = advanced # advanced, extended, or basic #sql_inheritance = on #default_with_oids = off ! #escape_string_warning = off # warn about backslashes in string literals ! #standard_conforming_strings = off # interpret string literals according to ANSI/ISO standards # - Other Platforms & Clients - Index: src/bin/psql/psqlscan.l =================================================================== RCS file: /projects/cvsroot/pgsql/src/bin/psql/psqlscan.l,v retrieving revision 1.15 diff -c -r1.15 psqlscan.l *** src/bin/psql/psqlscan.l 26 Jun 2005 19:16:06 -0000 1.15 --- src/bin/psql/psqlscan.l 25 Jan 2006 22:22:58 -0000 *************** *** 122,127 **** --- 122,129 ---- #define ECHO emit(yytext, yyleng) + bool standard_conforming_strings; + %} %option 8bit *************** *** 154,160 **** * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string ! * quoted strings * $foo$ quoted strings */ --- 156,163 ---- * extended C-style comments * delimited identifiers (double-quoted identifiers) * hexadecimal numeric string ! * standard quoted strings ! * extended quoted strings (support backslash escape sequences) * $foo$ quoted strings */ *************** *** 162,167 **** --- 165,171 ---- %x xc %x xd %x xh + %x xe %x xq %x xdolq /* Additional exclusive states for psql only: lex backslash commands */ *************** *** 244,249 **** --- 248,257 ---- /* Quoted string that allows backslash escapes */ xestart [eE]{quote} + xeinside [^\\']+ + xeescape [\\][^0-7] + xeoctesc [\\][0-7]{1,3} + xehexesc [\\]x[0-9A-Fa-f]{1,2} /* Extended quote * xqdouble implements embedded quote, '''' *************** *** 251,259 **** xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqescape [\\][^0-7] ! xqoctesc [\\][0-7]{1,3} ! xqhexesc [\\]x[0-9A-Fa-f]{1,2} /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string --- 259,265 ---- xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqbackslash [\\] /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string *************** *** 448,485 **** } {xqstart} { ! BEGIN(xq); ECHO; } {xestart} { ! BEGIN(xq); ECHO; } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(INITIAL); ECHO; } ! {xqdouble} { ECHO; } {xqinside} { ECHO; } ! {xqescape} { ECHO; } ! {xqoctesc} { ECHO; } ! {xqhexesc} { ECHO; } ! {quotecontinue} { ECHO; } ! . { /* This is only needed for \ just before EOF */ ECHO; } --- 454,504 ---- } {xqstart} { ! /* ! * if (standard_conforming_strings) ! */ ! BEGIN(xq); ! /* ! * else ! * BEGIN(xe); ! */ ECHO; } {xestart} { ! BEGIN(xe); ECHO; } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(INITIAL); ECHO; } ! {xqdouble} { ECHO; } {xqinside} { ECHO; } ! {xqbackslash} { ! ECHO; ! } ! {xeinside} { ECHO; } ! {xeescape} { ECHO; } ! {xeoctesc} { ECHO; } ! {xehexesc} { ECHO; } ! {quotecontinue} { ! ECHO; ! } ! . { /* This is only needed for \ just before EOF */ ECHO; } *************** *** 858,870 **** "\\r" { appendPQExpBufferChar(output_buf, '\r'); } "\\f" { appendPQExpBufferChar(output_buf, '\f'); } ! {xqoctesc} { /* octal case */ appendPQExpBufferChar(output_buf, (char) strtol(yytext + 1, NULL, 8)); } ! {xqhexesc} { /* hex case */ appendPQExpBufferChar(output_buf, (char) strtol(yytext + 2, NULL, 16)); --- 877,889 ---- "\\r" { appendPQExpBufferChar(output_buf, '\r'); } "\\f" { appendPQExpBufferChar(output_buf, '\f'); } ! {xeoctesc} { /* octal case */ appendPQExpBufferChar(output_buf, (char) strtol(yytext + 1, NULL, 8)); } ! {xehexesc} { /* hex case */ appendPQExpBufferChar(output_buf, (char) strtol(yytext + 2, NULL, 16)); *************** *** 1128,1133 **** --- 1147,1156 ---- result = PSCAN_INCOMPLETE; *prompt = PROMPT_SINGLEQUOTE; break; + case xe: + result = PSCAN_INCOMPLETE; + *prompt = PROMPT_SINGLEQUOTE; + break; case xdolq: result = PSCAN_INCOMPLETE; *prompt = PROMPT_DOLLARQUOTE; Index: src/include/utils/guc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/guc.h,v retrieving revision 1.63 diff -c -r1.63 guc.h *** src/include/utils/guc.h 15 Oct 2005 02:49:46 -0000 1.63 --- src/include/utils/guc.h 25 Jan 2006 22:22:58 -0000 *************** *** 121,126 **** --- 121,127 ---- extern bool default_with_oids; extern bool escape_string_warning; + extern bool standard_conforming_strings; extern int log_min_error_statement; extern int log_min_messages; Index: src/interfaces/ecpg/preproc/pgc.l =================================================================== RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v retrieving revision 1.137 diff -c -r1.137 pgc.l *** src/interfaces/ecpg/preproc/pgc.l 5 Oct 2005 14:58:36 -0000 1.137 --- src/interfaces/ecpg/preproc/pgc.l 25 Jan 2006 22:22:58 -0000 *************** *** 30,35 **** --- 30,36 ---- static int xcdepth = 0; /* depth of nesting in slash-star comments */ static char *dolqstart; /* current $foo$ quote start string */ bool escape_string_warning; + bool standard_conforming_strings; static bool warn_on_first_escape; /* *************** *** 96,102 **** * extended C-style comments - thomas 1997-07-12 * delimited identifiers (double-quoted identifiers) - thomas 1997-10-27 * hexadecimal numeric string - thomas 1997-11-16 ! * quoted strings - thomas 1997-07-30 * $foo$ quoted strings */ --- 97,104 ---- * extended C-style comments - thomas 1997-07-12 * delimited identifiers (double-quoted identifiers) - thomas 1997-10-27 * hexadecimal numeric string - thomas 1997-11-16 ! * standard quoted strings - thomas 1997-07-30 ! * extended quoted strings (support backslash escape sequences) * $foo$ quoted strings */ *************** *** 105,110 **** --- 107,113 ---- %x xd %x xdc %x xh + %x xe %x xq %x xdolq %x xpre *************** *** 125,130 **** --- 128,137 ---- /* Quoted string that allows backslash escapes */ xestart [eE]{quote} + xeinside [^\\']+ + xeescape [\\][^0-7] + xeoctesc [\\][0-7]{1,3} + xehexesc [\\]x[0-9A-Fa-f]{1,2} /* C version of hex number */ xch 0[xX][0-9A-Fa-f]* *************** *** 135,143 **** xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqescape [\\][^0-7] ! xqoctesc [\\][0-7]{1,3} ! xqhexesc [\\]x[0-9A-Fa-f]{1,2} /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string --- 142,148 ---- xqstart {quote} xqdouble {quote}{quote} xqinside [^\\']+ ! xqbackslash [\\] /* $foo$ style quotes ("dollar quoting") * The quoted string starts with $foo$ where "foo" is an optional string *************** *** 405,447 **** warn_on_first_escape = true; token_start = yytext; state_before = YYSTATE; ! BEGIN(xq); startlit(); } {xestart} { warn_on_first_escape = false; token_start = yytext; state_before = YYSTATE; ! BEGIN(xq); startlit(); } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(state_before); yylval.str = mm_strdup(literalbuf); return SCONST; } ! {xqdouble} { addlitchar('\''); } {xqinside} { addlit(yytext, yyleng); } ! {xqescape} { check_escape_warning(); addlit(yytext, yyleng); } ! {xqoctesc} { check_escape_warning(); addlit(yytext, yyleng); } ! {xqhexesc} { check_escape_warning(); addlit(yytext, yyleng); } ! {quotecontinue} { /* ignore */ } ! . { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } ! <> { mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted string"); } {dolqfailed} { /* throw back all but the initial "$" */ yyless(1); --- 410,460 ---- warn_on_first_escape = true; token_start = yytext; state_before = YYSTATE; ! if (standard_conforming_strings) ! BEGIN(xq); ! else ! BEGIN(xe); startlit(); } {xestart} { warn_on_first_escape = false; token_start = yytext; state_before = YYSTATE; ! BEGIN(xe); startlit(); } ! {quotestop} | ! {quotefail} { yyless(1); BEGIN(state_before); yylval.str = mm_strdup(literalbuf); return SCONST; } ! {xqdouble} { addlitchar('\''); } {xqinside} { addlit(yytext, yyleng); } ! {xeinside} { addlit(yytext, yyleng); } ! {xqbackslash} { ! check_escape_warning(); ! addlitchar('\\'); ! } ! {xeescape} { check_escape_warning(); addlit(yytext, yyleng); } ! {xeoctesc} { check_escape_warning(); addlit(yytext, yyleng); } ! {xehexesc} { check_escape_warning(); addlit(yytext, yyleng); } ! {quotecontinue} { /* ignore */ } ! . { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } ! <> { mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted string"); } {dolqfailed} { /* throw back all but the initial "$" */ yyless(1);