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