Rewrite ProcessConfigFile() to avoid misbehavior at EOF, as per report
from Andrus Moor. The former state-machine-style coding wasn't actually doing much except obscuring the control flow, and it didn't extend readily to fix this case, so I just took it out. Also, add a YY_FLUSH_BUFFER call to ensure the lexer is reset correctly if the previous scan failed partway through the file.
This commit is contained in:
parent
0898033b1e
commit
fc6da31ae1
@ -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.32 2005/09/21 20:33:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.33 2006/01/01 19:52:40 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
@ -126,7 +126,7 @@ void
|
|||||||
ProcessConfigFile(GucContext context)
|
ProcessConfigFile(GucContext context)
|
||||||
{
|
{
|
||||||
int elevel;
|
int elevel;
|
||||||
int token, parse_state;
|
int token;
|
||||||
char *opt_name, *opt_value;
|
char *opt_name, *opt_value;
|
||||||
struct name_value_pair *item, *head, *tail;
|
struct name_value_pair *item, *head, *tail;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -144,94 +144,93 @@ ProcessConfigFile(GucContext context)
|
|||||||
else
|
else
|
||||||
elevel = ERROR;
|
elevel = ERROR;
|
||||||
|
|
||||||
fp = AllocateFile(ConfigFileName, "r");
|
fp = AllocateFile(ConfigFileName, "r");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not open configuration file \"%s\": %m",
|
errmsg("could not open configuration file \"%s\": %m",
|
||||||
ConfigFileName)));
|
ConfigFileName)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse
|
* Parse
|
||||||
*/
|
*/
|
||||||
yyin = fp;
|
yyin = fp;
|
||||||
parse_state = 0;
|
YY_FLUSH_BUFFER; /* in case we abandoned a prior scan */
|
||||||
head = tail = NULL;
|
head = tail = NULL;
|
||||||
opt_name = opt_value = NULL;
|
opt_name = opt_value = NULL;
|
||||||
ConfigFileLineno = 1;
|
ConfigFileLineno = 1;
|
||||||
|
|
||||||
while ((token = yylex()))
|
/* This loop iterates once per logical line */
|
||||||
|
while ((token = yylex()))
|
||||||
{
|
{
|
||||||
switch(parse_state)
|
if (token == GUC_EOL) /* empty or comment line */
|
||||||
{
|
continue;
|
||||||
case 0: /* no previous input */
|
|
||||||
if (token == GUC_EOL) /* empty line */
|
|
||||||
continue;
|
|
||||||
if (token != GUC_ID && token != GUC_QUALIFIED_ID)
|
|
||||||
goto parse_error;
|
|
||||||
opt_name = pstrdup(yytext);
|
|
||||||
parse_state = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* found name */
|
/* first token on line is option name */
|
||||||
/* ignore equals sign */
|
if (token != GUC_ID && token != GUC_QUALIFIED_ID)
|
||||||
if (token == GUC_EQUALS)
|
goto parse_error;
|
||||||
token = yylex();
|
opt_name = pstrdup(yytext);
|
||||||
|
|
||||||
if (token != GUC_ID &&
|
/* next we have an optional equal sign; discard if present */
|
||||||
token != GUC_STRING &&
|
token = yylex();
|
||||||
token != GUC_INTEGER &&
|
if (token == GUC_EQUALS)
|
||||||
token != GUC_REAL &&
|
token = yylex();
|
||||||
token != GUC_UNQUOTED_STRING)
|
|
||||||
goto parse_error;
|
|
||||||
if (token == GUC_STRING) /* strip quotes and escapes */
|
|
||||||
opt_value = GUC_scanstr(yytext);
|
|
||||||
else
|
|
||||||
opt_value = pstrdup(yytext);
|
|
||||||
parse_state = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* now we'd like an end of line */
|
/* now we must have the option value */
|
||||||
if (token != GUC_EOL)
|
if (token != GUC_ID &&
|
||||||
goto parse_error;
|
token != GUC_STRING &&
|
||||||
|
token != GUC_INTEGER &&
|
||||||
|
token != GUC_REAL &&
|
||||||
|
token != GUC_UNQUOTED_STRING)
|
||||||
|
goto parse_error;
|
||||||
|
if (token == GUC_STRING) /* strip quotes and escapes */
|
||||||
|
opt_value = GUC_scanstr(yytext);
|
||||||
|
else
|
||||||
|
opt_value = pstrdup(yytext);
|
||||||
|
|
||||||
if (strcmp(opt_name, "custom_variable_classes") == 0)
|
/* now we'd like an end of line, or possibly EOF */
|
||||||
{
|
token = yylex();
|
||||||
/*
|
if (token != GUC_EOL && token != 0)
|
||||||
* This variable must be processed first as it controls
|
goto parse_error;
|
||||||
* the validity of other variables; so apply immediately.
|
|
||||||
*/
|
|
||||||
if (!set_config_option(opt_name, opt_value, context,
|
|
||||||
PGC_S_FILE, false, true))
|
|
||||||
{
|
|
||||||
pfree(opt_name);
|
|
||||||
pfree(opt_value);
|
|
||||||
FreeFile(fp);
|
|
||||||
goto cleanup_exit;
|
|
||||||
}
|
|
||||||
pfree(opt_name);
|
|
||||||
pfree(opt_value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* append to list */
|
|
||||||
item = palloc(sizeof *item);
|
|
||||||
item->name = opt_name;
|
|
||||||
item->value = opt_value;
|
|
||||||
item->next = NULL;
|
|
||||||
if (!head)
|
|
||||||
head = item;
|
|
||||||
else
|
|
||||||
tail->next = item;
|
|
||||||
tail = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_state = 0;
|
/* OK, save the option name and value */
|
||||||
break;
|
if (strcmp(opt_name, "custom_variable_classes") == 0)
|
||||||
}
|
{
|
||||||
|
/*
|
||||||
|
* This variable must be processed first as it controls
|
||||||
|
* the validity of other variables; so apply immediately.
|
||||||
|
*/
|
||||||
|
if (!set_config_option(opt_name, opt_value, context,
|
||||||
|
PGC_S_FILE, false, true))
|
||||||
|
{
|
||||||
|
pfree(opt_name);
|
||||||
|
pfree(opt_value);
|
||||||
|
FreeFile(fp);
|
||||||
|
goto cleanup_exit;
|
||||||
|
}
|
||||||
|
pfree(opt_name);
|
||||||
|
pfree(opt_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* append to list */
|
||||||
|
item = palloc(sizeof *item);
|
||||||
|
item->name = opt_name;
|
||||||
|
item->value = opt_value;
|
||||||
|
item->next = NULL;
|
||||||
|
if (!head)
|
||||||
|
head = item;
|
||||||
|
else
|
||||||
|
tail->next = item;
|
||||||
|
tail = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* break out of loop if read EOF, else loop for next line */
|
||||||
|
if (token == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeFile(fp);
|
FreeFile(fp);
|
||||||
@ -239,14 +238,14 @@ ProcessConfigFile(GucContext context)
|
|||||||
/*
|
/*
|
||||||
* Check if all options are valid
|
* Check if all options are valid
|
||||||
*/
|
*/
|
||||||
for(item = head; item; item=item->next)
|
for(item = head; item; item=item->next)
|
||||||
{
|
{
|
||||||
if (!set_config_option(item->name, item->value, context,
|
if (!set_config_option(item->name, item->value, context,
|
||||||
PGC_S_FILE, false, false))
|
PGC_S_FILE, false, false))
|
||||||
goto cleanup_exit;
|
goto cleanup_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we got here all the options parsed okay, so apply them. */
|
/* If we got here all the options parsed okay, so apply them. */
|
||||||
for(item = head; item; item=item->next)
|
for(item = head; item; item=item->next)
|
||||||
{
|
{
|
||||||
set_config_option(item->name, item->value, context,
|
set_config_option(item->name, item->value, context,
|
||||||
@ -260,7 +259,7 @@ ProcessConfigFile(GucContext context)
|
|||||||
parse_error:
|
parse_error:
|
||||||
FreeFile(fp);
|
FreeFile(fp);
|
||||||
free_name_value_list(head);
|
free_name_value_list(head);
|
||||||
if (token == GUC_EOL)
|
if (token == GUC_EOL || token == 0)
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error in file \"%s\" line %u, near end of line",
|
errmsg("syntax error in file \"%s\" line %u, near end of line",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user