diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index e6e11090ab..bb9207a777 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -45,6 +45,8 @@ static unsigned int ConfigFileLineno; static const char *GUC_flex_fatal_errmsg; static sigjmp_buf *GUC_flex_fatal_jmp; +static void FreeConfigVariable(ConfigVariable *item); + /* flex fails to supply a prototype for yylex, so provide one */ int GUC_yylex(void); @@ -151,14 +153,66 @@ ProcessConfigFile(GucContext context) * file is in the data directory, we can't read it until the DataDir has * been set. */ - if (DataDir && - !ParseConfigFile(PG_AUTOCONF_FILENAME, NULL, false, 0, elevel, - &head, &tail)) + if (DataDir) { - /* Syntax error(s) detected in the file, so bail out */ - error = true; - ErrorConfFile = PG_AUTOCONF_FILENAME; - goto cleanup_list; + if (!ParseConfigFile(PG_AUTOCONF_FILENAME, NULL, false, 0, elevel, + &head, &tail)) + { + /* Syntax error(s) detected in the file, so bail out */ + error = true; + ErrorConfFile = PG_AUTOCONF_FILENAME; + goto cleanup_list; + } + } + else + { + ConfigVariable *prev = NULL; + + /* + * Pick up only the data_directory if DataDir is not set, which + * means that the configuration file is read for the first time and + * PG_AUTOCONF_FILENAME file cannot be read yet. In this case, + * we shouldn't pick any settings except the data_directory + * from postgresql.conf because they might be overwritten + * with the settings in PG_AUTOCONF_FILENAME file which will be + * read later. OTOH, since it's ensured that data_directory doesn't + * exist in PG_AUTOCONF_FILENAME file, it will never be overwritten + * later. + */ + for (item = head; item;) + { + ConfigVariable *ptr = item; + + item = item->next; + if (strcmp(ptr->name, "data_directory") != 0) + { + if (prev == NULL) + head = ptr->next; + else + { + prev->next = ptr->next; + /* + * On removing last item in list, we need to update tail + * to ensure that list will be maintianed. + */ + if (prev->next == NULL) + tail = prev; + } + FreeConfigVariable(ptr); + } + else + prev = ptr; + } + + /* + * Quick exit if data_directory is not present in list. + * + * Don't remember when we last successfully loaded the config file in + * this case because that time will be set soon by subsequent load of + * the config file. + */ + if (head == NULL) + return; } /* @@ -677,7 +731,7 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, *tail_p = prev_item; } - pfree(cur_item); + FreeConfigVariable(cur_item); break; } } @@ -857,6 +911,21 @@ cleanup: return status; } +/* + * Free a ConfigVariable + */ +static void +FreeConfigVariable(ConfigVariable *item) +{ + if (item != NULL) + { + pfree(item->name); + pfree(item->value); + pfree(item->filename); + pfree(item); + } +} + /* * Free a list of ConfigVariables, including the names and the values */ @@ -870,10 +939,7 @@ FreeConfigVariables(ConfigVariable *list) { ConfigVariable *next = item->next; - pfree(item->name); - pfree(item->value); - pfree(item->filename); - pfree(item); + FreeConfigVariable(item); item = next; } } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9aa1bc4702..60e4354f6b 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4339,6 +4339,13 @@ SelectConfigFiles(const char *userDoption, const char *progname) return false; } + /* + * Read the configuration file for the first time. This time only + * data_directory parameter is picked up to determine the data directory + * so that we can read PG_AUTOCONF_FILENAME file next time. Then don't + * forget to read the configuration file again later to pick up all the + * parameters. + */ ProcessConfigFile(PGC_POSTMASTER); /*