*** a/src/backend/access/transam/xact.c --- b/src/backend/access/transam/xact.c *************** *** 1844,1849 **** CommitTransaction(void) --- 1844,1851 ---- /* close large objects before lower-level cleanup */ AtEOXact_LargeObject(true); + AtEOXact_UpdateAutoConfFiles(true); + /* * Mark serializable transaction as complete for predicate locking * purposes. This should be done as late as we can put it and still allow *************** *** 2302,2307 **** AbortTransaction(void) --- 2304,2310 ---- AtAbort_Portals(); AtEOXact_LargeObject(false); AtAbort_Notify(); + AtEOXact_UpdateAutoConfFiles(false); AtEOXact_RelationMap(false); /* *** a/src/backend/commands/dbcommands.c --- b/src/backend/commands/dbcommands.c *************** *** 58,65 **** --- 58,74 ---- #include "utils/snapmgr.h" #include "utils/syscache.h" #include "utils/tqual.h" + #include "utils/guc_tables.h" + #include "utils/memutils.h" + /* lock file used in edit postgresql.auto.conf */ + struct lock_file + { + int fd; + char filename[MAXPGPATH]; + }; + typedef struct { Oid src_dboid; /* source (template) DB */ *************** *** 72,77 **** typedef struct --- 81,88 ---- Oid dest_tsoid; /* tablespace we are trying to move to */ } movedb_failure_params; + static struct lock_file *lockConfFile = NULL; + /* non-export function prototypes */ static void createdb_failure_callback(int code, Datum arg); static void movedb(const char *dbname, const char *tblspcname); *************** *** 86,91 **** static void remove_dbtablespaces(Oid db_id); --- 97,108 ---- static bool check_db_file_conflict(Oid db_id); static int errdetail_busy_db(int notherbackends, int npreparedxacts); + static int commit_lock_file(struct lock_file * lk); + static void rollback_lock_file(struct lock_file * lk); + static int close_lock_file(struct lock_file * lk); + static void writeAutoConffile(int fd, ConfigVariable **head_p, char *config_file); + static void replace_autoline(ConfigVariable **head_p, ConfigVariable **tail_p, + char *config_file, char *name, char *value, bool value_is_string); /* * CREATE DATABASE *************** *** 1434,1439 **** AlterDatabaseSet(AlterDatabaseSetStmt *stmt) --- 1451,1778 ---- /* + * create a postgres.auto.conf.lock file for postgres.auto.conf + * file so that it act as an lock to prevent concurrent edit on + * postgres.auto.conf file + */ + static int + lock_confile(struct lock_file * lk, const char *path, int flags) + { + int ntries = 0; + + strcpy(lk->filename, path); + strcat(lk->filename, CONF_LOCK_POSTFIX); + + tryAgain: + lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0600); + if (0 > lk->fd) + { + /* + * Couldn't create the lock file. Probably it already exists. If so + * wait for some time + */ + ntries++; + if ((errno != EEXIST && errno != EACCES) || ntries > 100) + { + if (errno != EEXIST) + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not create lock file \"%s\": %m", + lk->filename))); + } + else + { + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not create lock file \"%s\": %m ", lk->filename), + errhint("May be too many concurrent edit into file happening, please wait!! and retry" + "or .lock is file accidently left there please clean the file from config_dir"))); + } + + lk->filename[0] = 0; + } + else + { + pg_usleep(100000); /* in total wait for 10sec */ + goto tryAgain; + } + } + + return lk->fd; + } + + /* function to close the postgres.auto.conf.lock file */ + int + close_lock_file(struct lock_file * lk) + { + int fd = lk->fd; + + lk->fd = -1; + return close(fd); + } + + + /* + * On commit, rename postgres.auto.conf.lock to postgres.auto.conf + * As postgres.auto.conf.lock contains updated parameter values. + */ + int + commit_lock_file(struct lock_file * lk) + { + char result_file[MAXPGPATH]; + size_t i; + + if (lk->fd >= 0 && close_lock_file(lk)) + return -1; + strcpy(result_file, lk->filename); + i = strlen(result_file) - 5; /* remove .lock charecters */ + result_file[i] = 0; + if (rename(lk->filename, result_file)) + return -1; + lk->filename[0] = 0; + return 0; + } + + + /* + * On rollback, Delete the postgres.auto.conf.lock file, As we did not + * modifed anything in postgres.auto.conf + */ + void + rollback_lock_file(struct lock_file * lk) + { + if (lk->filename[0]) + { + if (lk->fd >= 0) + { + /* cloase the file */ + close(lk->fd); + } + + /* now remove the file */ + unlink(lk->filename); + } + + lk->filename[0] = 0; + } + + + /* Write updated configuration parameter values into postgres.auto.conf.lock */ + static void + writeAutoConffile(int fd, ConfigVariable **head_p, char *config_file) + { + ConfigVariable *item; + StringInfoData buf; + + initStringInfo(&buf); + + for (item = *head_p; item != NULL; item = item->next) + { + appendStringInfoString(&buf, item->name); + appendStringInfoString(&buf, " = "); + + if (true == item->value_is_string) + { + appendStringInfoString(&buf, "\'"); + appendStringInfoString(&buf, item->value); + appendStringInfoString(&buf, "\'"); + } + else + { + appendStringInfoString(&buf, item->value); + } + + appendStringInfoString(&buf, "\n"); + + if (write(fd, buf.data, buf.len) < 0) + { + ereport(ERROR, + (errmsg("failed to write into to \"postgresql.auto.conf.lock\" file"))); + } + + resetStringInfo(&buf); + } + + pfree(buf.data); + return; + } + + + /* + * Replace the updated configuration parameter value in postgres.auto.conf + * file lines. If it is new then append extra line at the end of lines. + */ + static void + replace_autoline(ConfigVariable **head_p, ConfigVariable **tail_p, + char *config_file, char *name, char *value, + bool value_is_string) + { + + ConfigVariable *item; + + if (NULL != *head_p) + { + for (item = *head_p; item != NULL; item = item->next) + { + if (strcmp(item->name, name) == 0) + { + pfree(item->value); + item->value = pstrdup(value); + return; + } + } + } + + item = palloc(sizeof *item); + item->name = pstrdup(name); + item->value = pstrdup(value); + item->value_is_string = value_is_string; + item->filename = pstrdup(config_file); + item->next = NULL; + + if (*head_p == NULL) + { + item->sourceline = 1; + *head_p = item; + } + else + { + item->sourceline = (*tail_p)->sourceline+1; + (*tail_p)->next = item; + } + + *tail_p = item; + + return; + } + + + /* + * Edit postgres.conf parameters WITH SQL commands "SET PERSISTENT" + * by adding new postgres.auto.conf file in include configuration directory + * which will be processed at the end of postgres.conf file + */ + void + set_config_file(VariableSetStmt *setstmt) + { + char *name; + char *value; + int fd = -1; + FILE *infile; + struct config_generic *record; + char abs_path[MAXPGPATH]; + ConfigVariable *head_p = NULL; + ConfigVariable *tail_p = NULL; + + /* + * This command is modifing the configuration file so no need of + * transaction properties, so not allowed inside a transaction. + */ + if (IsTransactionBlock()) + { + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("SET PERSISTENT command is not allowed inside a transaction"))); + } + + if (!superuser()) + { + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to execute SET PERSISTENT command")))); + } + + /* + * Validate the name and arguments [value1, value2 ... ]. + */ + + name = pstrdup(setstmt->name); + value = ExtractSetVariableArgs(setstmt); + + record = validate_conf_option(name, value); + if (!record) + ereport(ERROR, + (errmsg("invalid value for parameter \"%s\": \"%s\"", name, value))); + + /* Create the postgres.auto.conf.lock file */ + join_path_components(abs_path, data_directory, AutoConfigFileName); + canonicalize_path(abs_path); + + lockConfFile = MemoryContextAllocZero(TopTransactionContext, sizeof(struct lock_file)); + + fd = lock_confile(lockConfFile, abs_path, 0); + if (fd < 0) + { + pfree(lockConfFile); + lockConfFile = NULL; + ereport(ERROR, + (errmsg("\"postgresql.auto.conf.lock\" file creation failed"))); + } + + /* open postgres.auto.conf file */ + infile = AllocateFile(abs_path, "r"); + if (infile == NULL) + { + ereport(ERROR, + (errmsg("failed to open \"postgresql.auto.conf\" file"))); + } + + /* Parse the postgres.auto.conf file */ + ParseConfigFp(infile, abs_path, -1, LOG, &head_p, &tail_p); + + FreeFile(infile); + + /* replace with new value */ + replace_autoline(&head_p, &tail_p, abs_path, name, value, + (record->vartype == PGC_STRING) ? true : false); + + /* Write the New contents to postgres.auto.conf.lock file */ + writeAutoConffile(fd, &head_p, abs_path); + + /* + * On Commit, rename postgres.auto.conf.lock to postgres.auto.conf + * and On Rollback, delete the postgres.auto.conf.lock + */ + + return; + } + + /* + * This routine is called during transaction commit or abort. + * + * On commit, renames the .auto.conf.lock to .auto.conf, for updateding changes + * into .auto.conf file + * + * On abort, just delete the .auto.conf.lock file. + * + * NB: this should be the last step before actual transaction commit. + * If any error aborts the transaction after we run this code, the postmaster + * will still have received and cached the changed data; so minimize the + * window for such problems. + */ + void + AtEOXact_UpdateAutoConfFiles(bool isCommit) + { + if (lockConfFile) + { + if (isCommit) + { + if (commit_lock_file(lockConfFile) < 0) + ereport(ERROR, + (errmsg("commiting chages to \"postgresql.auto.conf\" failed"))); + } + else + { + rollback_lock_file(lockConfFile); + } + + pfree(lockConfFile); + lockConfFile = NULL; + } + } + + /* * ALTER DATABASE name OWNER TO newowner */ void *** a/src/backend/parser/gram.y --- b/src/backend/parser/gram.y *************** *** 564,571 **** static void processCASbits(int cas_bits, int location, const char *constrType, OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER ! PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION ! PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE QUOTE --- 564,571 ---- OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER ! PARSER PARTIAL PARTITION PASSING PASSWORD PERSISTENT PLACING PLANS ! POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE QUOTE *************** *** 1293,1298 **** VariableSetStmt: --- 1293,1307 ---- n->is_local = false; $$ = (Node *) n; } + | SET PERSISTENT var_name '=' var_list + { + VariableSetStmt *n = makeNode(VariableSetStmt); + n->kind = VAR_SET_VALUE; + n->name = $3; + n->args = $5; + n->is_persistent = true; + $$ = (Node *)n; + } ; set_rest: *************** *** 12586,12591 **** unreserved_keyword: --- 12595,12601 ---- | PARTITION | PASSING | PASSWORD + | PERSISTENT | PLANS | PRECEDING | PREPARE *** a/src/backend/postmaster/postmaster.c --- b/src/backend/postmaster/postmaster.c *************** *** 507,512 **** PostmasterMain(int argc, char *argv[]) --- 507,513 ---- char *userDoption = NULL; bool listen_addr_saved = false; int i; + char conf_lock_file[MAXPGPATH]; MyProcPid = PostmasterPid = getpid(); *************** *** 1163,1168 **** PostmasterMain(int argc, char *argv[]) --- 1164,1174 ---- */ RemovePgTempFiles(); + /* Remove postgres.auto.conf.lock file make be left over from last crash */ + strcpy(conf_lock_file, AutoConfigFileName); + strcat(conf_lock_file, CONF_LOCK_POSTFIX); + unlink(conf_lock_file); + /* * Remember postmaster startup time */ *** a/src/backend/replication/basebackup.c --- b/src/backend/replication/basebackup.c *************** *** 581,586 **** sendDir(char *path, int basepathlen, bool sizeonly) --- 581,592 ---- strlen(PG_TEMP_FILE_PREFIX)) == 0) continue; + /* skip lock files used in postgresql.auto.conf edit */ + if (strncmp(de->d_name, + "postgresql.auto.conf.lock", + strlen("postgresql.auto.conf.lock")) == 0) + continue; + /* * If there's a backup_label file, it belongs to a backup started by * the user with pg_start_backup(). It is *not* correct for this *** a/src/backend/tcop/utility.c --- b/src/backend/tcop/utility.c *************** *** 1145,1151 **** standard_ProcessUtility(Node *parsetree, break; case T_VariableSetStmt: ! ExecSetVariableStmt((VariableSetStmt *) parsetree); break; case T_VariableShowStmt: --- 1145,1158 ---- break; case T_VariableSetStmt: ! if (((VariableSetStmt *) parsetree)->is_persistent == true) ! { ! set_config_file((VariableSetStmt *) parsetree); ! } ! else ! { ! ExecSetVariableStmt((VariableSetStmt *) parsetree); ! } break; case T_VariableShowStmt: *** a/src/backend/utils/misc/guc-file.l --- b/src/backend/utils/misc/guc-file.l *************** *** 533,538 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, --- 533,539 ---- { char *opt_name = NULL; char *opt_value = NULL; + bool is_string = false; ConfigVariable *item; if (token == GUC_EOL) /* empty or comment line */ *************** *** 556,562 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, --- 557,566 ---- token != GUC_UNQUOTED_STRING) goto parse_error; if (token == GUC_STRING) /* strip quotes and escapes */ + { opt_value = GUC_scanstr(yytext); + is_string = true; + } else opt_value = pstrdup(yytext); *************** *** 620,625 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, --- 624,630 ---- item = palloc(sizeof *item); item->name = opt_name; item->value = opt_value; + item->value_is_string = is_string; item->filename = pstrdup(config_file); item->sourceline = ConfigFileLineno-1; item->next = NULL; *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** *** 5105,5110 **** config_enum_get_options(struct config_enum * record, const char *prefix, --- 5105,5260 ---- return retstr.data; } + /*given key and value validate the config value*/ + + struct config_generic * + validate_conf_option(const char *name, const char *value) + { + struct config_generic *record; + + record = find_option(name, true, LOG); + if (record == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("unrecognized configuration parameter \"%s\"", name))); + } + + if (record->context == PGC_INTERNAL) + { + ereport(ERROR, + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed", + name))); + } + + /* + * Evaluate value and set variable. + */ + switch (record->vartype) + { + + case PGC_BOOL: + { + struct config_bool *conf = (struct config_bool *) record; + bool newval; + void *newextra = NULL; + + if (value) + { + if (!parse_bool(value, &newval)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a Boolean value", + name))); + } + if (!call_bool_check_hook(conf, &newval, &newextra, + PGC_S_FILE, LOG)) + return NULL; + } + } + break; + + case PGC_INT: + { + struct config_int *conf = (struct config_int *) record; + int newval; + void *newextra = NULL; + + if (value) + { + const char *hintmsg; + + if (!parse_int(value, &newval, conf->gen.flags, &hintmsg)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for parameter \"%s\": \"%s\"", + name, value), + hintmsg ? errhint("%s", _(hintmsg)) : 0)); + } + if (newval < conf->min || newval > conf->max) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%d is outside the valid range for parameter \"%s\" (%d .. %d)", + newval, name, conf->min, conf->max))); + } + if (!call_int_check_hook(conf, &newval, &newextra, + PGC_S_FILE, LOG)) + return NULL; + } + } + + break; + + case PGC_REAL: + { + struct config_real *conf = (struct config_real *) record; + double newval; + void *newextra = NULL; + + if (value) + { + if (!parse_real(value, &newval)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" requires a numeric value", + name))); + } + if (newval < conf->min || newval > conf->max) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("%g is outside the valid range for parameter \"%s\" (%g .. %g)", + newval, name, conf->min, conf->max))); + } + if (!call_real_check_hook(conf, &newval, &newextra, + PGC_S_FILE, LOG)) + return NULL; + } + } + + break; + + case PGC_STRING: + { + struct config_string *conf = (struct config_string *) record; + char *newval; + void *newextra = NULL; + + if (value) + { + /* + * The value passed by the caller could be transient, so + * we always strdup it. + */ + newval = guc_strdup(LOG, value); + if (newval == NULL) + return NULL; + + /* + * The only built-in "parsing" check we have is to apply + * truncation if GUC_IS_NAME. + */ + if (conf->gen.flags & GUC_IS_NAME) + truncate_identifier(newval, strlen(newval), true); + + if (!call_string_check_hook(conf, &newval, &newextra, + PGC_S_FILE, LOG)) + { + free(newval); + return NULL; + } + } + } + } + + return record; + } + /* * Sets option `name' to given value. *** a/src/bin/initdb/initdb.c --- b/src/bin/initdb/initdb.c *************** *** 177,182 **** static const char *backend_options = "--single -F -O -c search_path=pg_catalog - --- 177,183 ---- static char bin_path[MAXPGPATH]; static char backend_exec[MAXPGPATH]; + char *make_absolute_path(const char *path); static void *pg_malloc(size_t size); static char *pg_strdup(const char *s); static char **replace_token(char **lines, *************** *** 1163,1168 **** setup_config(void) --- 1164,1171 ---- char repltok[MAXPGPATH]; char path[MAXPGPATH]; const char *default_timezone; + char *abs_data_dir; + FILE *autofile; fputs(_("creating configuration files ... "), stdout); fflush(stdout); *************** *** 1245,1255 **** setup_config(void) --- 1248,1284 ---- conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok); } + abs_data_dir = make_absolute_path(pg_data); + + snprintf(repltok, sizeof(repltok), "include_dir = '%s/config_dir'", + abs_data_dir); + conflines = replace_token(conflines, "#include_dir = 'conf.d'", repltok); + snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); writefile(path, conflines); chmod(path, S_IRUSR | S_IWUSR); + /* create a .auto for conf file */ + sprintf(path, "%s/config_dir/postgresql.auto.conf", pg_data); + autofile = fopen(path, PG_BINARY_W); + if (autofile == NULL) + { + fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"), + progname, path, strerror(errno)); + exit_nicely(); + } + + if (fclose(autofile)) + { + fprintf(stderr, _("%s: could not write file \"%s\": %s\n"), + progname, path, strerror(errno)); + exit_nicely(); + } + + chmod(path, S_IRUSR | S_IWUSR); + + free(conflines); *************** *** 2823,2828 **** check_need_password(const char *authmethodlocal, const char *authmethodhost) --- 2852,2933 ---- } } + /* + * If the given pathname isn't already absolute, make it so, interpreting + * it relative to the current working directory. + * + * Also canonicalizes the path. The result is always a malloc'd copy. + * + */ + char * + make_absolute_path(const char *path) + { + char *new; + + /* Returning null for null input is convenient for some callers */ + if (path == NULL) + return NULL; + + if (!is_absolute_path(path)) + { + char *buf; + size_t buflen; + + buflen = MAXPGPATH; + for (;;) + { + buf = malloc(buflen); + if (!buf) + { + fprintf(stderr, _("%s: Memory allocation failed\n"), + progname); + exit_nicely(); + } + + if (getcwd(buf, buflen)) + break; + else if (errno == ERANGE) + { + free(buf); + buflen *= 2; + continue; + } + else + { + free(buf); + fprintf(stderr, _("%s: could not get current working directory\n"), + progname); + exit_nicely(); + } + } + + new = malloc(strlen(buf) + strlen(path) + 2); + if (!new) + { + fprintf(stderr, _("%s: Memory allocation failed\n"), + progname); + exit_nicely(); + } + sprintf(new, "%s/%s", buf, path); + free(buf); + } + else + { + new = strdup(path); + if (!new) + { + fprintf(stderr, _("%s: Memory allocation failed\n"), + progname); + exit_nicely(); + } + } + + /* Make sure punctuation is canonical, too */ + canonicalize_path(new); + + return new; + } + int main(int argc, char *argv[]) { *************** *** 2887,2893 **** main(int argc, char *argv[]) "base", "base/1", "pg_tblspc", ! "pg_stat_tmp" }; progname = get_progname(argv[0]); --- 2992,2999 ---- "base", "base/1", "pg_tblspc", ! "pg_stat_tmp", ! "config_dir" }; progname = get_progname(argv[0]); *** a/src/include/commands/dbcommands.h --- b/src/include/commands/dbcommands.h *************** *** 58,63 **** extern void RenameDatabase(const char *oldname, const char *newname); --- 58,64 ---- extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId); + extern void set_config_file(VariableSetStmt *setstmt); extern Oid get_database_oid(const char *dbname, bool missingok); extern char *get_database_name(Oid dbid); *************** *** 67,70 **** extern void dbase_desc(StringInfo buf, uint8 xl_info, char *rec); --- 68,73 ---- extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype); + extern void AtEOXact_UpdateAutoConfFiles(bool isCommit); + #endif /* DBCOMMANDS_H */ *** a/src/include/nodes/parsenodes.h --- b/src/include/nodes/parsenodes.h *************** *** 1425,1430 **** typedef struct VariableSetStmt --- 1425,1431 ---- char *name; /* variable to be set */ List *args; /* List of A_Const nodes */ bool is_local; /* SET LOCAL? */ + bool is_persistent; /* SET PERSISTENT? */ } VariableSetStmt; /* ---------------------- *** a/src/include/parser/kwlist.h --- b/src/include/parser/kwlist.h *************** *** 279,284 **** PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD) --- 279,285 ---- PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD) PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD) PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD) + PG_KEYWORD("persistent", PERSISTENT, UNRESERVED_KEYWORD) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD) PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD) *** a/src/include/utils/guc.h --- b/src/include/utils/guc.h *************** *** 105,110 **** typedef struct ConfigVariable --- 105,111 ---- { char *name; char *value; + int value_is_string; char *filename; int sourceline; struct ConfigVariable *next; *************** *** 191,196 **** typedef enum --- 192,201 ---- #define GUC_NOT_WHILE_SEC_REST 0x8000 /* can't set if security restricted */ + /* postgresql.auto.file name and its lock */ + #define AutoConfigFileName "config_dir/postgresql.auto.conf" + #define CONF_LOCK_POSTFIX ".lock" + /* GUC vars that are actually declared in guc.c, rather than elsewhere */ extern bool log_duration; extern bool Debug_print_plan; *** a/src/include/utils/guc_tables.h --- b/src/include/utils/guc_tables.h *************** *** 260,265 **** extern void build_guc_variables(void); --- 260,267 ---- extern const char *config_enum_lookup_by_value(struct config_enum * record, int val); extern bool config_enum_lookup_by_name(struct config_enum * record, const char *value, int *retval); + extern struct config_generic * validate_conf_option(const char *name, + const char *value); #endif /* GUC_TABLES_H */