]> granicus.if.org Git - postgresql/commitdiff
Prevent duplicate escape-string warnings when using pg_stat_statements.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Jan 2015 23:10:47 +0000 (18:10 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Jan 2015 23:11:00 +0000 (18:11 -0500)
contrib/pg_stat_statements will sometimes run the core lexer a second time
on submitted statements.  Formerly, if you had standard_conforming_strings
turned off, this led to sometimes getting two copies of any warnings
enabled by escape_string_warning.  While this is probably no longer a big
deal in the field, it's a pain for regression testing.

To fix, change the lexer so it doesn't consult the escape_string_warning
GUC variable directly, but looks at a copy in the core_yy_extra_type state
struct.  Then, pg_stat_statements can change that copy to disable warnings
while it's redoing the lexing.

It seemed like a good idea to make this happen for all three of the GUCs
consulted by the lexer, not just escape_string_warning.  There's not an
immediate use-case for callers to adjust the other two AFAIK, but making
it possible is easy enough and seems like good future-proofing.

Arguably this is a bug fix, but there doesn't seem to be enough interest to
justify a back-patch.  We'd not be able to back-patch exactly as-is anyway,
for fear of breaking ABI compatibility of the struct.  (We could perhaps
back-patch the addition of only escape_string_warning by adding it at the
end of the struct, where there's currently alignment padding space.)

contrib/pg_stat_statements/pg_stat_statements.c
src/backend/parser/scan.l
src/include/parser/scanner.h

index 2629bfca34f1b77793bcf37b9bd7f5cc269b2a5a..95616b36914d52f710d64299c3207fe3e9508fd8 100644 (file)
@@ -2816,6 +2816,9 @@ fill_in_constant_lengths(pgssJumbleState *jstate, const char *query)
                                                         ScanKeywords,
                                                         NumScanKeywords);
 
+       /* we don't want to re-emit any escape string warnings */
+       yyextra.escape_string_warning = false;
+
        /* Search for each constant, in sequence */
        for (i = 0; i < jstate->clocations_count; i++)
        {
index 21a6f30e10cb94d3b878ce527a84b303ee6109de..a78ce03fbd5a4ef31a0b8984819366a60fe28849 100644 (file)
@@ -505,7 +505,7 @@ other                       .
                                        yyextra->warn_on_first_escape = true;
                                        yyextra->saw_non_ascii = false;
                                        SET_YYLLOC();
-                                       if (standard_conforming_strings)
+                                       if (yyextra->standard_conforming_strings)
                                                BEGIN(xq);
                                        else
                                                BEGIN(xe);
@@ -520,7 +520,7 @@ other                       .
                                }
 {xusstart}             {
                                        SET_YYLLOC();
-                                       if (!standard_conforming_strings)
+                                       if (!yyextra->standard_conforming_strings)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                 errmsg("unsafe use of string constant with Unicode escapes"),
@@ -622,8 +622,8 @@ other                       .
 <xe>{xeescape}  {
                                        if (yytext[1] == '\'')
                                        {
-                                               if (backslash_quote == BACKSLASH_QUOTE_OFF ||
-                                                       (backslash_quote == BACKSLASH_QUOTE_SAFE_ENCODING &&
+                                               if (yyextra->backslash_quote == BACKSLASH_QUOTE_OFF ||
+                                                       (yyextra->backslash_quote == BACKSLASH_QUOTE_SAFE_ENCODING &&
                                                         PG_ENCODING_IS_CLIENT_ONLY(pg_get_client_encoding())))
                                                        ereport(ERROR,
                                                                        (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
@@ -1074,6 +1074,10 @@ scanner_init(const char *str,
        yyext->keywords = keywords;
        yyext->num_keywords = num_keywords;
 
+       yyext->backslash_quote = backslash_quote;
+       yyext->escape_string_warning = escape_string_warning;
+       yyext->standard_conforming_strings = standard_conforming_strings;
+
        /*
         * Make a scan buffer with special termination needed by flex.
         */
@@ -1433,7 +1437,7 @@ check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner)
 {
        if (ychar == '\'')
        {
-               if (yyextra->warn_on_first_escape && escape_string_warning)
+               if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
                        ereport(WARNING,
                                        (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                         errmsg("nonstandard use of \\' in a string literal"),
@@ -1443,7 +1447,7 @@ check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner)
        }
        else if (ychar == '\\')
        {
-               if (yyextra->warn_on_first_escape && escape_string_warning)
+               if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
                        ereport(WARNING,
                                        (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                         errmsg("nonstandard use of \\\\ in a string literal"),
@@ -1458,7 +1462,7 @@ check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner)
 static void
 check_escape_warning(core_yyscan_t yyscanner)
 {
-       if (yyextra->warn_on_first_escape && escape_string_warning)
+       if (yyextra->warn_on_first_escape && yyextra->escape_string_warning)
                ereport(WARNING,
                                (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                 errmsg("nonstandard use of escape in a string literal"),
index 02e8764213504a8402e49ce006c05974cf35c15f..e6724bc588ea07b542fdb1f98af65cba48dba352 100644 (file)
@@ -77,6 +77,16 @@ typedef struct core_yy_extra_type
        const ScanKeyword *keywords;
        int                     num_keywords;
 
+       /*
+        * Scanner settings to use.  These are initialized from the corresponding
+        * GUC variables by scanner_init().  Callers can modify them after
+        * scanner_init() if they don't want the scanner's behavior to follow the
+        * prevailing GUC settings.
+        */
+       int                     backslash_quote;
+       bool            escape_string_warning;
+       bool            standard_conforming_strings;
+
        /*
         * literalbuf is used to accumulate literal values when multiple rules are
         * needed to parse a single literal.  Call startlit() to reset buffer to