pg_parser_continue_on_error_v2a.patch
application/octet-stream
Filename: pg_parser_continue_on_error_v2a.patch
Type: application/octet-stream
Part: 1
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index 78907b9..ec001d6 100644
*** a/src/backend/utils/misc/guc-file.l
--- b/src/backend/utils/misc/guc-file.l
*************** ProcessConfigFile(GucContext context)
*** 111,135 ****
char *cvc = NULL;
struct config_string *cvc_struct;
int i;
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
! if (context == PGC_SIGHUP)
! {
! /*
! * To avoid cluttering the log, only the postmaster bleats loudly
! * about problems with the config file.
! */
! 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
--- 111,139 ----
char *cvc = NULL;
struct config_string *cvc_struct;
int i;
+ bool OK = true;
+ /* Config files are only processes on startup (by the postmaster)
+ * and on SIGUP (by the postmaster and backends)
+ */
Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
+ Assert(!(context == PGC_POSTMATER && IsUnderPostmaster));
! /*
! * To avoid cluttering the log, only the postmaster bleats loudly
! * about problems with the config file.
! */
! elevel = IsUnderPostmaster ? DEBUG2 : LOG;
!
! /* Parse the file into a list of option names and values.
! * We continue even if we hit a parse errors because we
! * also want to report invalid value in the parts we
! * could parse
! */
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
*************** ProcessConfigFile(GucContext context)
*** 161,167 ****
goto cleanup_list;
if (!call_string_check_hook(cvc_struct, &cvc, &extra,
PGC_S_FILE, elevel))
! goto cleanup_list;
if (extra)
free(extra);
}
--- 165,171 ----
goto cleanup_list;
if (!call_string_check_hook(cvc_struct, &cvc, &extra,
PGC_S_FILE, elevel))
! OK = false;
if (extra)
free(extra);
}
*************** ProcessConfigFile(GucContext context)
*** 201,207 ****
(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
--- 205,211 ----
(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
*************** ProcessConfigFile(GucContext context)
*** 221,228 ****
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
--- 225,235 ----
if (!set_config_option(item->name, item->value, context,
PGC_S_FILE, GUC_ACTION_SET, false))
! OK = false;
}
+ /* 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
*************** ProcessConfigFile(GucContext context)
*** 345,350 ****
--- 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")));
}
/*
*************** ParseConfigFile(const char *config_file,
*** 437,442 ****
--- 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,
*************** bool
*** 447,455 ****
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
*************** ParseConfigFp(FILE *fp, const char *conf
*** 458,463 ****
--- 475,481 ----
yy_switch_to_buffer(lex_buffer);
ConfigFileLineno = 1;
+ errorcount = 0;
/* This loop iterates once per logical line */
while ((token = yylex()))
*************** ParseConfigFp(FILE *fp, const char *conf
*** 512,523 ****
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);
*************** ParseConfigFp(FILE *fp, const char *conf
*** 576,602 ****
/* 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 != 0 && 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 (errorcount >= 100)
+ break;
}
/* successful completion of parsing */
yy_delete_buffer(lex_buffer);
! return (errorcount == 0);
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 92391ed..fc195c5 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** config_enum_get_options(struct config_en
*** 5055,5061 ****
*
* If there is an error (non-existing option, invalid value) then an
* ereport(ERROR) is thrown *unless* this is called in a context where we
! * don't want to ereport (currently, startup or SIGHUP config file reread).
* In that case we write a suitable error message via ereport(LOG) and
* return false. This is working around the deficiencies in the ereport
* mechanism, so don't blame me. In all other cases, the function
--- 5055,5061 ----
*
* If there is an error (non-existing option, invalid value) then an
* ereport(ERROR) is thrown *unless* this is called in a context where we
! * don't want to ereport (currently, settings defaults and cfg file reading)
* In that case we write a suitable error message via ereport(LOG) and
* return false. This is working around the deficiencies in the ereport
* mechanism, so don't blame me. In all other cases, the function
*************** set_config_option(const char *name, cons
*** 5074,5080 ****
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