diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index eb9e022..0bf9372 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -882,24 +882,7 @@ PostmasterMain(int argc, char *argv[]) /* And switch working directory into it */ ChangeToDataDir(); - - /* - * Check for invalid combinations of GUC settings. - */ - if (ReservedBackends >= MaxConnections) - { - write_stderr("%s: superuser_reserved_connections (%d) must be less than max_connections (%d)\n", - progname, - ReservedBackends, MaxConnections); - ExitPostmaster(1); - } - if (XLogArchiveMode > ARCHIVE_MODE_OFF && wal_level == WAL_LEVEL_MINIMAL) - ereport(ERROR, - (errmsg("WAL archival cannot be enabled when wal_level is \"minimal\""))); - if (max_wal_senders > 0 && wal_level == WAL_LEVEL_MINIMAL) - ereport(ERROR, - (errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"replica\" or \"logical\""))); /* * Other one-time internal sanity checks can go here, if they are fast. * (Put any slow processing further down, after postmaster.pid creation.) diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 2178e1c..77e47e9 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -7828,6 +7828,108 @@ write_auto_conf_file(int fd, const char *filename, ConfigVariable *head) pfree(buf.data); } +/* + * This function traverses a list of parameters + * to check for invalid config combinations + */ +void +check_for_invalid_config_combinations(ConfigVariable **conf) { + ConfigVariable *item, *next; + + for (item = *conf; item != NULL; item = next) + { + next = item->next; + ConfigVariable *pitem, *pnext; + + /* + * We could avoid the O(N^2) behavior here with some additional + * state, but it seems unlikely to be worth the trouble. + */ + for (pitem = *conf; pitem != NULL; pitem = pnext) + { + pnext = pitem->next; + if (!pitem->ignore) { + if (guc_name_compare(item->name, "superuser_reserved_connections") == 0 && + guc_name_compare(pitem->name, "max_connections") == 0) { + int reserved_backends; + int max_connections; + if (!parse_int(item->value, &max_connections, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (!parse_int(pitem->value, &reserved_backends, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (reserved_backends >= max_connections) + { + ereport(ERROR, + (errmsg("%s: superuser_reserved_connections (%d) must be less than max_connections (%d)\n", + progname, + ReservedBackends, MaxConnections))); + } + } + + if (guc_name_compare(item->name, "archive_mode") == 0 && + guc_name_compare(pitem->name, "wal_level") == 0) { + int WalLevel; + int xlog_archive_mode; + if (!parse_int(item->value, &xlog_archive_mode, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (!parse_int(pitem->value, &WalLevel, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (xlog_archive_mode > ARCHIVE_MODE_OFF && WalLevel == WAL_LEVEL_MINIMAL) + { + ereport(ERROR, + (errmsg("WAL archival cannot be enabled when wal_level is \"minimal\""))); + } + } + + if (guc_name_compare(item->name, "max_wal_senders") == 0 && + guc_name_compare(pitem->name, "wal_level") == 0) { + int WalLevel; + int max_wal_senders; + if (!parse_int(item->value, &max_wal_senders, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (!parse_int(pitem->value, &WalLevel, 0, NULL)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + item->name, item->value))); + } + + if (max_wal_senders > 0 && WalLevel == WAL_LEVEL_MINIMAL) + { + ereport(ERROR, + (errmsg("WAL streaming (max_wal_senders > 0) requires wal_level \"replica\" or \"logical\""))); + } + } + } + } + } +} + /* * Update the given list of configuration parameters, adding, replacing * or deleting the entry for item "name" (delete if "value" == NULL). @@ -7988,7 +8090,7 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value for parameter \"%s\": \"%s\"", name, value))); if (record->vartype == PGC_STRING && newval.stringval != NULL) free(newval.stringval); if (newextra) @@ -8051,8 +8153,16 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) AutoConfFileName))); FreeFile(infile); + + /* + * Check to ensure change is valid in combination + * with other configuration settings. + */ + ConfigVariable *conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3); + check_for_invalid_config_combinations(&conf); } /* * Now, replace any existing entry with the new value, or add it if * not present. diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index 6791e0c..ef10364 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -354,6 +354,7 @@ extern bool SelectConfigFiles(const char *userDoption, const char *progname); extern void ResetAllOptions(void); extern void AtStart_GUC(void); extern int NewGUCNestLevel(void); +extern void check_for_invalid_config_combinations(ConfigVariable **conf); extern void AtEOXact_GUC(bool isCommit, int nestLevel); extern void BeginReportingGUCOptions(void); extern void ParseLongOption(const char *string, char **name, char **value);