Fix postgresql.conf lexer to accept doubled single quotes in literal
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Sep 2005 20:33:34 +0000 (20:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 21 Sep 2005 20:33:34 +0000 (20:33 +0000)
strings.  This is consistent with SQL conventions, and since Bruce
already changed initdb in a way that assumed it worked like this, seems
we'd better make it work like this.

doc/src/sgml/config.sgml
src/backend/utils/misc/guc-file.l

index 52852ee6c2481417a442f8dbc0de30fa846b9b7c..6e9cc4817db4d841ebf562144f6a7ecb6061044d 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.18 2005/09/19 17:21:46 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.19 2005/09/21 20:33:33 tgl Exp $
 -->
 <chapter Id="runtime-config">
   <title>Run-time Configuration</title>
@@ -45,7 +45,8 @@ search_path = '$user, public'
     value is optional. Whitespace is insignificant and blank lines are
     ignored. Hash marks (<literal>#</literal>) introduce comments
     anywhere.  Parameter values that are not simple identifiers or
-    numbers must be single-quoted.
+    numbers must be single-quoted.  To embed a single quote in a parameter
+    value, write either two quotes (preferred) or backslash-quote.
   </para>
 
    <para>
index 32d47c44cdaf4cbf299872afa6c53583c0f1f731..f5fed2e267ead0ec7054d8d568a3168ea2c2f8e0 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.31 2005/07/08 18:41:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.32 2005/09/21 20:33:34 tgl Exp $
  */
 
 %{
@@ -38,7 +38,7 @@ enum {
 
 /* prototype, so compiler is happy with our high warnings setting */
 int GUC_yylex(void);
-static char *GUC_scanstr(char *);
+static char *GUC_scanstr(const char *s);
 %}
 
 %option 8bit
@@ -64,7 +64,7 @@ ID              {LETTER}{LETTER_OR_DIGIT}*
 QUALIFIED_ID    {ID}"."{ID}
 
 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
-STRING          \'([^'\n]|\\.)*\'
+STRING          \'([^'\\\n]|\\.|\'\')*\'
 
 %%
 
@@ -181,22 +181,16 @@ ProcessConfigFile(GucContext context)
                 if (token == GUC_EQUALS)
                     token = yylex();
 
-                if (token != GUC_ID && token != GUC_STRING && 
+                if (token != GUC_ID &&
+                                       token != GUC_STRING && 
                                        token != GUC_INTEGER && 
                                        token != GUC_REAL && 
                                        token != GUC_UNQUOTED_STRING)
                     goto parse_error;
-                opt_value = pstrdup(yytext);
-                               if (token == GUC_STRING)
-                               {
-                                       /* remove the beginning and ending quote/apostrophe */
-                                       /* first: shift the whole thing down one character */
-                                       memmove(opt_value, opt_value+1, strlen(opt_value)-1);
-                                       /* second: null out the 2 characters we shifted */
-                                       opt_value[strlen(opt_value)-2] = '\0';
-                                       /* do the escape thing.  pfree()'s the pstrdup above */
-                                       opt_value = GUC_scanstr(opt_value);
-                               }
+                               if (token == GUC_STRING)        /* strip quotes and escapes */
+                                       opt_value = GUC_scanstr(yytext);
+                               else
+                                       opt_value = pstrdup(yytext);
                 parse_state = 2;
                 break;
 
@@ -280,34 +274,33 @@ ProcessConfigFile(GucContext context)
 
 
 
-/* ----------------
+/*
  *             scanstr
  *
- * if the string passed in has escaped codes, map the escape codes to actual
- * chars
+ * Strip the quotes surrounding the given string, and collapse any embedded
+ * '' sequences and backslash escapes.
  *
  * the string returned is palloc'd and should eventually be pfree'd by the
- * caller; also we assume we should pfree the input string.
- * ----------------
+ * caller.
  */
-
 static char *
-GUC_scanstr(char *s)
+GUC_scanstr(const char *s)
 {
        char       *newStr;
        int                     len,
                                i,
                                j;
 
-       if (s == NULL || s[0] == '\0')
-       {
-               if (s != NULL)
-                       pfree(s);
-               return pstrdup("");
-       }
+       Assert(s != NULL && s[0] == '\'');
        len = strlen(s);
+       Assert(len >= 2);
+       Assert(s[len-1] == '\'');
+
+       /* Skip the leading quote; we'll handle the trailing quote below */
+       s++, len--;
 
-       newStr = palloc(len + 1);       /* string cannot get longer */
+       /* Since len still includes trailing quote, this is enough space */
+       newStr = palloc(len);
 
        for (i = 0, j = 0; i < len; i++)
        {
@@ -354,13 +347,21 @@ GUC_scanstr(char *s)
                                default:
                                        newStr[j] = s[i];
                                        break;
-                               }
                        }                                       /* switch */
+               }
+               else if (s[i] == '\'' && s[i+1] == '\'')
+               {
+                       /* doubled quote becomes just one quote */
+                       newStr[j] = s[++i];
+               }
                else
                        newStr[j] = s[i];
                j++;
        }
-       newStr[j] = '\0';
-       pfree(s);
+
+       /* We copied the ending quote to newStr, so replace with \0 */
+       Assert(j > 0 && j <= len);
+       newStr[--j] = '\0';
+
        return newStr;
 }