Fix postgresql.conf lexer to accept doubled single quotes in literal

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.
This commit is contained in:
Tom Lane 2005-09-21 20:33:34 +00:00
parent dbf952860e
commit 1128f55659
2 changed files with 36 additions and 34 deletions

View 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"> <chapter Id="runtime-config">
<title>Run-time Configuration</title> <title>Run-time Configuration</title>
@ -45,7 +45,8 @@ search_path = '$user, public'
value is optional. Whitespace is insignificant and blank lines are value is optional. Whitespace is insignificant and blank lines are
ignored. Hash marks (<literal>#</literal>) introduce comments ignored. Hash marks (<literal>#</literal>) introduce comments
anywhere. Parameter values that are not simple identifiers or 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>
<para> <para>

View File

@ -4,7 +4,7 @@
* *
* Copyright (c) 2000-2005, PostgreSQL Global Development Group * 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 */ /* prototype, so compiler is happy with our high warnings setting */
int GUC_yylex(void); int GUC_yylex(void);
static char *GUC_scanstr(char *); static char *GUC_scanstr(const char *s);
%} %}
%option 8bit %option 8bit
@ -64,7 +64,7 @@ ID {LETTER}{LETTER_OR_DIGIT}*
QUALIFIED_ID {ID}"."{ID} QUALIFIED_ID {ID}"."{ID}
UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])* UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
STRING \'([^'\n]|\\.)*\' STRING \'([^'\\\n]|\\.|\'\')*\'
%% %%
@ -181,22 +181,16 @@ ProcessConfigFile(GucContext context)
if (token == GUC_EQUALS) if (token == GUC_EQUALS)
token = yylex(); token = yylex();
if (token != GUC_ID && token != GUC_STRING && if (token != GUC_ID &&
token != GUC_STRING &&
token != GUC_INTEGER && token != GUC_INTEGER &&
token != GUC_REAL && token != GUC_REAL &&
token != GUC_UNQUOTED_STRING) token != GUC_UNQUOTED_STRING)
goto parse_error; goto parse_error;
if (token == GUC_STRING) /* strip quotes and escapes */
opt_value = GUC_scanstr(yytext);
else
opt_value = pstrdup(yytext); 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);
}
parse_state = 2; parse_state = 2;
break; break;
@ -280,34 +274,33 @@ ProcessConfigFile(GucContext context)
/* ---------------- /*
* scanstr * scanstr
* *
* if the string passed in has escaped codes, map the escape codes to actual * Strip the quotes surrounding the given string, and collapse any embedded
* chars * '' sequences and backslash escapes.
* *
* the string returned is palloc'd and should eventually be pfree'd by the * 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 * static char *
GUC_scanstr(char *s) GUC_scanstr(const char *s)
{ {
char *newStr; char *newStr;
int len, int len,
i, i,
j; j;
if (s == NULL || s[0] == '\0') Assert(s != NULL && s[0] == '\'');
{
if (s != NULL)
pfree(s);
return pstrdup("");
}
len = strlen(s); len = strlen(s);
Assert(len >= 2);
Assert(s[len-1] == '\'');
newStr = palloc(len + 1); /* string cannot get longer */ /* Skip the leading quote; we'll handle the trailing quote below */
s++, len--;
/* Since len still includes trailing quote, this is enough space */
newStr = palloc(len);
for (i = 0, j = 0; i < len; i++) for (i = 0, j = 0; i < len; i++)
{ {
@ -354,13 +347,21 @@ GUC_scanstr(char *s)
default: default:
newStr[j] = s[i]; newStr[j] = s[i];
break; break;
}
} /* switch */ } /* switch */
}
else if (s[i] == '\'' && s[i+1] == '\'')
{
/* doubled quote becomes just one quote */
newStr[j] = s[++i];
}
else else
newStr[j] = s[i]; newStr[j] = s[i];
j++; 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; return newStr;
} }