parser_continue_on_errors_v2.diff
application/octet-stream
Filename: parser_continue_on_errors_v2.diff
Type: application/octet-stream
Part: 0
*** a/src/backend/utils/misc/guc-file.l
--- b/src/backend/utils/misc/guc-file.l
***************
*** 110,116 **** ProcessConfigFile(GucContext context)
*tail;
char *cvc = NULL;
struct config_string *cvc_struct;
! int i;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
--- 110,117 ----
*tail;
char *cvc = NULL;
struct config_string *cvc_struct;
! int i;
! bool OK = true;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
***************
*** 123,135 **** ProcessConfigFile(GucContext context)
elevel = IsUnderPostmaster ? DEBUG2 : LOG;
}
else
! elevel = ERROR;
/* Parse the file into a list of option names and values */
head = tail = NULL;
if (!ParseConfigFile(ConfigFileName, NULL, 0, elevel, &head, &tail))
! goto cleanup_list;
/*
* We need the proposed new value of custom_variable_classes to check
--- 124,136 ----
elevel = IsUnderPostmaster ? DEBUG2 : LOG;
}
else
! elevel = LOG;
/* Parse the file into a list of option names and values */
head = tail = NULL;
if (!ParseConfigFile(ConfigFileName, NULL, 0, elevel, &head, &tail))
! OK = false;
/*
* We need the proposed new value of custom_variable_classes to check
***************
*** 161,167 **** ProcessConfigFile(GucContext context)
goto cleanup_list;
if (!call_string_check_hook(cvc_struct, &cvc, &extra,
PGC_S_FILE, elevel))
! goto cleanup_list;
if (extra)
free(extra);
}
--- 162,168 ----
goto cleanup_list;
if (!call_string_check_hook(cvc_struct, &cvc, &extra,
PGC_S_FILE, elevel))
! OK = false;
if (extra)
free(extra);
}
***************
*** 201,207 **** ProcessConfigFile(GucContext context)
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"",
item->name)));
! goto cleanup_list;
}
/*
* 2. There is no GUC entry. If we called set_config_option then
--- 202,208 ----
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"",
item->name)));
! OK = false;
}
/*
* 2. There is no GUC entry. If we called set_config_option then
***************
*** 221,228 **** ProcessConfigFile(GucContext context)
if (!set_config_option(item->name, item->value, context,
PGC_S_FILE, GUC_ACTION_SET, false))
! goto cleanup_list;
}
/*
* Check for variables having been removed from the config file, and
--- 222,235 ----
if (!set_config_option(item->name, item->value, context,
PGC_S_FILE, GUC_ACTION_SET, false))
! OK = false;
! /* stop at the first error if we are postmaster's child */
! if (IsUnderPostmaster && !OK)
! break;
}
+ /* Don't change configuration options if errors were detected earlier */
+ if (!OK)
+ goto cleanup_list;
/*
* Check for variables having been removed from the config file, and
***************
*** 345,350 **** ProcessConfigFile(GucContext context)
--- 352,361 ----
FreeConfigVariables(head);
if (cvc)
free(cvc);
+ /* If we got an error during postmaster's start - complain and bail out */
+ if (!OK && context == PGC_POSTMASTER)
+ ereport(ERROR,
+ (errmsg("errors detected while parsing configuration files")));
}
/*
***************
*** 437,442 **** ParseConfigFile(const char *config_file, const char *calling_file,
--- 448,459 ----
* already been ereport'd, it is only necessary for the caller to clean up
* its own state and release the name/value pairs list.
*
+ * If elevel < ERROR then we don't return immediately on the first error,
+ * although we do return after comming across 100 of them. This is to prevent
+ * trashing out logs when parsing a completely bogus file. We consider all
+ * parse errors in "includes" as a single one for simplicity, it's unlikely we
+ * ever come across the bogus file with valid include directives.
+ *
* Note: if elevel >= ERROR then an error will not return control to the
* caller, and internal state such as open files will not be cleaned up.
* This case occurs only during postmaster or standalone-backend startup,
***************
*** 447,455 **** bool
ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
ConfigVariable **head_p, ConfigVariable **tail_p)
{
- bool OK = true;
YY_BUFFER_STATE lex_buffer;
! int token;
/*
* Parse
--- 464,472 ----
ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
ConfigVariable **head_p, ConfigVariable **tail_p)
{
YY_BUFFER_STATE lex_buffer;
! int token,
! errorcount;
/*
* Parse
***************
*** 458,463 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
--- 475,481 ----
yy_switch_to_buffer(lex_buffer);
ConfigFileLineno = 1;
+ errorcount = 0;
/* This loop iterates once per logical line */
while ((token = yylex()))
***************
*** 512,523 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
if (!ParseConfigFile(opt_value, config_file,
depth + 1, elevel,
head_p, tail_p))
! {
! pfree(opt_name);
! pfree(opt_value);
! OK = false;
! goto cleanup_exit;
! }
yy_switch_to_buffer(lex_buffer);
ConfigFileLineno = save_ConfigFileLineno;
pfree(opt_name);
--- 530,536 ----
if (!ParseConfigFile(opt_value, config_file,
depth + 1, elevel,
head_p, tail_p))
! errorcount++;
yy_switch_to_buffer(lex_buffer);
ConfigFileLineno = save_ConfigFileLineno;
pfree(opt_name);
***************
*** 576,602 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
/* break out of loop if read EOF, else loop for next line */
if (token == 0)
break;
}
/* successful completion of parsing */
- goto cleanup_exit;
-
- parse_error:
- if (token == GUC_EOL || token == 0)
- ereport(elevel,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error in file \"%s\" line %u, near end of line",
- config_file, ConfigFileLineno - 1)));
- else
- ereport(elevel,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
- config_file, ConfigFileLineno, yytext)));
- OK = false;
-
- cleanup_exit:
yy_delete_buffer(lex_buffer);
! return OK;
}
--- 589,625 ----
/* break out of loop if read EOF, else loop for next line */
if (token == 0)
break;
+ /* skip over parse_error if we made it this far without errors */
+ continue;
+
+ parse_error:
+ if (token == GUC_EOL || token == 0)
+ ereport(elevel,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error in file \"%s\" line %u, near end of line",
+ config_file, ConfigFileLineno - 1)));
+ else
+ ereport(elevel,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
+ config_file, ConfigFileLineno, yytext)));
+ errorcount++;
+ /* fast forward till the next EOL/EOF */
+ while (token && token != GUC_EOL)
+ token = yylex();
+
+ /* break out of loop on EOF */
+ if (token == 0)
+ break;
+
+ /* avoid producing too much noise when parsing a bogus file */
+ if (IsUnderPostmaster || errorcount >= 100)
+ break;
}
/* successful completion of parsing */
yy_delete_buffer(lex_buffer);
! return (errorcount == 0);
}
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 5074,5080 **** set_config_option(const char *name, const char *value,
bool prohibitValueChange = false;
bool makeDefault;
! if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
{
/*
* To avoid cluttering the log, only the postmaster bleats loudly
--- 5074,5080 ----
bool prohibitValueChange = false;
bool makeDefault;
! if (source == PGC_S_FILE || source == PGC_S_DEFAULT)
{
/*
* To avoid cluttering the log, only the postmaster bleats loudly