*** a/doc/src/sgml/keywords.sgml
--- b/doc/src/sgml/keywords.sgml
***************
*** 3388,3393 ****
--- 3388,3401 ----
+
+ PERSISTENT
+ non-reserved
+
+
+
+
+
PLACING
reserved
non-reserved
*** a/doc/src/sgml/ref/set.sgml
--- b/doc/src/sgml/ref/set.sgml
***************
*** 21,28 **** PostgreSQL documentation
! SET [ SESSION | LOCAL ] configuration_parameter { TO | = } { value | 'value' | DEFAULT }
! SET [ SESSION | LOCAL ] TIME ZONE { timezone | LOCAL | DEFAULT }
--- 21,28 ----
! SET [ SESSION | LOCAL | PERSISTENT ] configuration_parameter { TO | = } { value | 'value' | DEFAULT }
! SET [ SESSION | LOCAL | PERSISTENT ] TIME ZONE { timezone | LOCAL | DEFAULT }
***************
*** 50,55 **** SET [ SESSION | LOCAL ] TIME ZONE { timezone
+ The SET PERSISTENT write the configuration parameter values to
+ postgresql.auto.conf file. with DEFAULT write the
+ configuration parameter values to default value in postgresql.auto.conf file.
+ For deleting configuration entry in postgresql.auto.conf file use the
+ RESET PERSISTENT. The values will be effective after reload of
+ server configuration (SIGHUP) or server startup.
+
+
+
The effects of SET LOCAL last only till the end of
the current transaction, whether committed or not. A special case is
SET followed by SET LOCAL within
***************
*** 98,105 **** SET [ SESSION | LOCAL ] TIME ZONE { timezone
Specifies that the command takes effect for the current session.
! (This is the default if neither SESSION> nor
! LOCAL> appears.)
--- 107,114 ----
Specifies that the command takes effect for the current session.
! (This is the default option, if any of SESSION>,
! LOCAL> or PERSISTENT> are not provided.)
***************
*** 119,124 **** SET [ SESSION | LOCAL ] TIME ZONE { timezone
+ PERSISTENT>
+
+
+ Writes updated configuration paramters in postgresql.auto.conf.
+ These configuration parameters takes effect after reload of configuration
+ file (SIGHUP) or in next server start based on type of configuration parameter modified.
+
+
+
+
+
configuration_parameter
***************
*** 154,160 **** SET [ SESSION | LOCAL ] TIME ZONE { timezone
SCHEMA
! SET SCHEMA 'value>'> is an alias for
SET search_path TO value>>. Only one
schema can be specified using this syntax.
--- 174,180 ----
SCHEMA
! SET [ PERSISTENT ] SCHEMA 'value>'> is an alias for
SET search_path TO value>>. Only one
schema can be specified using this syntax.
***************
*** 164,170 **** SET [ SESSION | LOCAL ] TIME ZONE { timezone
NAMES
! SET NAMES value>> is an alias for
SET client_encoding TO value>>.
--- 184,190 ----
NAMES
! SET [ PERSISTENT ] NAMES value>> is an alias for
SET client_encoding TO value>>.
***************
*** 192,198 **** SELECT setseed(value);
TIME ZONE
! SET TIME ZONE value>> is an alias
for SET timezone TO value>>. The
syntax SET TIME ZONE allows special syntax
for the time zone specification. Here are examples of valid
--- 212,218 ----
TIME ZONE
! SET [ PERSISTENT ] TIME ZONE value>> is an alias
for SET timezone TO value>>. The
syntax SET TIME ZONE allows special syntax
for the time zone specification. Here are examples of valid
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 3264,3269 **** _copyVariableSetStmt(const VariableSetStmt *from)
--- 3264,3270 ----
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(is_local);
+ COPY_SCALAR_FIELD(is_persistent);
return newnode;
}
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 1555,1560 **** _equalVariableSetStmt(const VariableSetStmt *a, const VariableSetStmt *b)
--- 1555,1561 ----
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(is_local);
+ COMPARE_SCALAR_FIELD(is_persistent);
return true;
}
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 394,400 **** static void processCASbits(int cas_bits, int location, const char *constrType,
%type insert_rest
! %type set_rest set_rest_more SetResetClause FunctionSetResetClause
%type TableElement TypedTableElement ConstraintElem TableFuncElement
ForeignTableElement
--- 394,400 ----
%type insert_rest
! %type set_rest set_rest_common set_rest_more SetResetClause FunctionSetResetClause
%type TableElement TypedTableElement ConstraintElem TableFuncElement
ForeignTableElement
***************
*** 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,1304 ----
n->is_local = false;
$$ = (Node *) n;
}
+ | SET PERSISTENT set_rest_common
+ {
+ VariableSetStmt *n = $3;
+ n->is_persistent = true;
+ $$ = (Node *) n;
+ }
;
set_rest:
***************
*** 1315,1321 **** set_rest:
| set_rest_more
;
! set_rest_more: /* Generic SET syntaxes: */
var_name TO var_list
{
VariableSetStmt *n = makeNode(VariableSetStmt);
--- 1321,1327 ----
| set_rest_more
;
! set_rest_common: /* common SET syntaxes: */
var_name TO var_list
{
VariableSetStmt *n = makeNode(VariableSetStmt);
***************
*** 1346,1358 **** set_rest_more: /* Generic SET syntaxes: */
n->name = $1;
$$ = n;
}
- | var_name FROM CURRENT_P
- {
- VariableSetStmt *n = makeNode(VariableSetStmt);
- n->kind = VAR_SET_CURRENT;
- n->name = $1;
- $$ = n;
- }
/* Special syntaxes mandated by SQL standard: */
| TIME ZONE zone_value
{
--- 1352,1357 ----
***************
*** 1365,1378 **** set_rest_more: /* Generic SET syntaxes: */
n->kind = VAR_SET_DEFAULT;
$$ = n;
}
- | CATALOG_P Sconst
- {
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("current database cannot be changed"),
- parser_errposition(@2)));
- $$ = NULL; /*not reached*/
- }
| SCHEMA Sconst
{
VariableSetStmt *n = makeNode(VariableSetStmt);
--- 1364,1369 ----
***************
*** 1381,1386 **** set_rest_more: /* Generic SET syntaxes: */
--- 1372,1404 ----
n->args = list_make1(makeStringConst($2, @2));
$$ = n;
}
+ | XML_P OPTION document_or_content
+ {
+ VariableSetStmt *n = makeNode(VariableSetStmt);
+ n->kind = VAR_SET_VALUE;
+ n->name = "xmloption";
+ n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
+ $$ = n;
+ }
+ ;
+
+ set_rest_more: /* Generic SET syntaxes: */
+ set_rest_common
+ | var_name FROM CURRENT_P
+ {
+ VariableSetStmt *n = makeNode(VariableSetStmt);
+ n->kind = VAR_SET_CURRENT;
+ n->name = $1;
+ $$ = n;
+ }
+ | CATALOG_P Sconst
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("current database cannot be changed"),
+ parser_errposition(@2)));
+ $$ = NULL; /*not reached*/
+ }
| NAMES opt_encoding
{
VariableSetStmt *n = makeNode(VariableSetStmt);
***************
*** 1415,1428 **** set_rest_more: /* Generic SET syntaxes: */
n->name = "session_authorization";
$$ = n;
}
- | XML_P OPTION document_or_content
- {
- VariableSetStmt *n = makeNode(VariableSetStmt);
- n->kind = VAR_SET_VALUE;
- n->name = "xmloption";
- n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
- $$ = n;
- }
/* Special syntaxes invented by PostgreSQL: */
| TRANSACTION SNAPSHOT Sconst
{
--- 1433,1438 ----
***************
*** 12590,12595 **** unreserved_keyword:
--- 12600,12606 ----
| PARTITION
| PASSING
| PASSWORD
+ | PERSISTENT
| PLANS
| PRECEDING
| PREPARE
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 2552,2557 **** reaper(SIGNAL_ARGS)
--- 2552,2569 ----
continue;
}
+ /* Delete the postgresql.auto.conf.lock file if exists */
+ {
+ char LockFileName[MAXPGPATH];
+
+ strlcpy(LockFileName, ConfigFileName, sizeof(LockFileName));
+ get_parent_directory(LockFileName);
+ join_path_components(LockFileName, LockFileName, AutoConfigLockFilename);
+ canonicalize_path(LockFileName);
+
+ unlink(LockFileName);
+ }
+
/*
* Startup succeeded, commence normal operations
*/
*** a/src/backend/replication/basebackup.c
--- b/src/backend/replication/basebackup.c
***************
*** 736,741 **** sendDir(char *path, int basepathlen, bool sizeonly)
--- 736,747 ----
strlen(PG_TEMP_FILE_PREFIX)) == 0)
continue;
+ /* skip lock files used in postgresql.auto.conf edit */
+ if (strncmp(de->d_name,
+ PGAUTOCONFLOCK,
+ sizeof(PGAUTOCONFLOCK)) == 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/utils/misc/guc-file.l
--- b/src/backend/utils/misc/guc-file.l
***************
*** 41,46 **** enum {
--- 41,47 ----
GUC_ERROR = 100
};
+ static bool is_config_dir_parsed = false;
static unsigned int ConfigFileLineno;
static const char *GUC_flex_fatal_errmsg;
static sigjmp_buf *GUC_flex_fatal_jmp;
***************
*** 137,142 **** ProcessConfigFile(GucContext context)
--- 138,145 ----
/* Parse the file into a list of option names and values */
head = tail = NULL;
+ is_config_dir_parsed = false;
+
if (!ParseConfigFile(ConfigFileName, NULL, true, 0, elevel, &head, &tail))
{
/* Syntax error(s) detected in the file, so bail out */
***************
*** 144,149 **** ProcessConfigFile(GucContext context)
--- 147,159 ----
goto cleanup_list;
}
+ if (!is_config_dir_parsed)
+ {
+ ereport(WARNING,
+ (errmsg("Default \"config_dir\" is not present in postgresql.conf."
+ "Any configuration value changed with SET PERSISTENT command will not be effective.")));
+ }
+
/*
* Mark all extant GUC variables as not present in the config file.
* We need this so that we can tell below which ones have been removed
***************
*** 367,373 **** ProcessConfigFile(GucContext context)
* path, return an absolute one. We consider the location to be relative to
* the directory holding the calling file.
*/
! static char *
AbsoluteConfigLocation(const char *location, const char *calling_file)
{
char abs_path[MAXPGPATH];
--- 377,383 ----
* path, return an absolute one. We consider the location to be relative to
* the directory holding the calling file.
*/
! char *
AbsoluteConfigLocation(const char *location, const char *calling_file)
{
char abs_path[MAXPGPATH];
***************
*** 411,416 **** ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
--- 421,427 ----
{
bool OK = true;
FILE *fp;
+ char *ConfigAutoFileName;
/*
* Reject too-deep include nesting depth. This is just a safety check
***************
*** 427,432 **** ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
--- 438,449 ----
}
config_file = AbsoluteConfigLocation(config_file,calling_file);
+
+ /* Checking for the postgresql.auto.conf file is parsed or not */
+ ConfigAutoFileName = AbsoluteConfigLocation(AutoConfigFileName, ConfigFileName);
+ if (depth == 1 && strcmp(ConfigAutoFileName, config_file) == 0)
+ is_config_dir_parsed = true;
+
fp = AllocateFile(config_file, "r");
if (!fp)
{
***************
*** 533,538 **** ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
--- 550,556 ----
{
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,
--- 574,583 ----
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,
--- 641,647 ----
item = palloc(sizeof *item);
item->name = opt_name;
item->value = opt_value;
+ item->is_quoted = 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
***************
*** 63,68 ****
--- 63,69 ----
#include "storage/bufmgr.h"
#include "storage/standby.h"
#include "storage/fd.h"
+ #include "storage/lwlock.h"
#include "storage/proc.h"
#include "storage/predicate.h"
#include "tcop/tcopprot.h"
***************
*** 3348,3353 **** static void ShowAllGUCConfig(DestReceiver *dest);
--- 3349,3359 ----
static char *_ShowOption(struct config_generic * record, bool use_units);
static bool validate_option_array_item(const char *name, const char *value,
bool skipIfNoPermissions);
+ static int create_conf_lock_file(const char *LockFileName);
+ static void write_auto_conf_file(int fd, ConfigVariable **head_p);
+ static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
+ char *config_file, char *name, char *value, bool is_quoted);
+ static void set_config_file(VariableSetStmt *setstmt);
/*
***************
*** 4120,4125 **** SelectConfigFiles(const char *userDoption, const char *progname)
--- 4126,4140 ----
return false;
}
+ /* Remove postgresql.auto.conf.lock file make be left over from last crash */
+ if (!IsUnderPostmaster)
+ {
+ char *LockFileName;
+
+ LockFileName = AbsoluteConfigLocation(AutoConfigLockFilename, ConfigFileName);
+ unlink(LockFileName);
+ }
+
ProcessConfigFile(PGC_POSTMASTER);
/*
***************
*** 5094,5099 **** config_enum_get_options(struct config_enum * record, const char *prefix,
--- 5109,5293 ----
return retstr.data;
}
+ /*
+ * Validates configuration parameter and value, incase of source is default
+ * returns the default value in string format.
+ */
+ struct config_generic *
+ validate_conf_option(const char *name, 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;
+ }
+ }
+ }
+ break;
+ case PGC_ENUM:
+ {
+ struct config_enum *conf = (struct config_enum *) record;
+ int newval;
+ void *newextra = NULL;
+
+ if (value)
+ {
+ if (!config_enum_lookup_by_name(conf, value, &newval))
+ {
+ char *hintmsg;
+
+ hintmsg = config_enum_get_options(conf,
+ "Available values: ",
+ ".", ", ");
+
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid value for parameter \"%s\": \"%s\"",
+ name, value),
+ hintmsg ? errhint("%s", _(hintmsg)) : 0));
+
+ if (hintmsg)
+ pfree(hintmsg);
+ return 0;
+ }
+ if (!call_enum_check_hook(conf, &newval, &newextra,
+ PGC_S_FILE, LOG))
+ return 0;
+ }
+ }
+ }
+
+ return record;
+ }
+
/*
* Sets option `name' to given value.
***************
*** 5897,5902 **** set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
--- 6091,6380 ----
}
/*
+ * Creates auto conf lock file used for protecting modification of
+ * postgresql.auto.conf file.
+ */
+ static int
+ create_conf_lock_file(const char *LockFileName)
+ {
+ int fd;
+
+ fd = open(LockFileName, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ {
+ /* Couldn't create the lock file. Probably it already exists */
+ if (errno != EEXIST)
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not create lock file \"%s\": %m",
+ LockFileName)));
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not create lock file \"%s\": %m ", LockFileName),
+ 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")));
+ }
+ }
+
+ return fd;
+ }
+
+
+ /* Write updated configuration parameter values into postgresql.auto.conf.lock */
+ static void
+ write_auto_conf_file(int fd, ConfigVariable **head_p)
+ {
+ ConfigVariable *item;
+ StringInfoData buf;
+
+ initStringInfo(&buf);
+
+ for (item = *head_p; item != NULL; item = item->next)
+ {
+ appendStringInfoString(&buf, item->name);
+ appendStringInfoString(&buf, " = ");
+
+ if (true == item->is_quoted)
+ {
+ 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);
+ }
+
+ if (pg_fsync(fd) != 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not fsync file \"postgresql.auto.conf.lock\": %m")));
+
+
+ pfree(buf.data);
+ return;
+ }
+
+
+ /*
+ * Replace the updated configuration parameter value in postgresql.auto.conf
+ * file lines. If it is new then append extra line at the end of lines.
+ */
+ static void
+ replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
+ char *config_file, char *name, char *value,
+ bool is_quoted)
+ {
+ ConfigVariable *item,
+ *prev = NULL;
+
+ if (NULL != *head_p)
+ {
+ for (item = *head_p; item != NULL; item = item->next)
+ {
+ if (strcmp(item->name, name) == 0)
+ {
+ pfree(item->value);
+ if (value)
+ {
+ /* update the parameter value */
+ item->value = pstrdup(value);
+ }
+ else
+ {
+ /* delete the configuration parameter from list */
+ if (*head_p == item)
+ {
+ *head_p = item->next;
+ }
+ else
+ {
+ prev->next = item->next;
+ }
+
+ if (*tail_p == item)
+ {
+ *tail_p = prev;
+ }
+ pfree(item->name);
+ pfree(item->filename);
+ pfree(item);
+ }
+ return;
+ }
+ prev = item;
+ }
+ }
+
+ if (NULL == value)
+ {
+ return;
+ }
+
+ item = palloc(sizeof *item);
+ item->name = pstrdup(name);
+ item->value = pstrdup(value);
+ item->is_quoted = is_quoted;
+ 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;
+ }
+
+
+ /*
+ * Persist the configuration parameter value.
+ * Writes the value of configuration parameter in postgresql.auto.conf.lock file.
+ * .lock file is used to disallow changing of file by multiple backends.
+ * On Success, rename postgresql.auto.conf.lock to postgresql.auto.conf
+ * and On Failure, delete the postgresql.auto.conf.lock
+ */
+ static void
+ set_config_file(VariableSetStmt *setstmt)
+ {
+ char *name;
+ char *value;
+ int lockfd = -1;
+ FILE *infile;
+ struct config_generic *record;
+ ConfigVariable *head_p = NULL;
+ ConfigVariable *tail_p = NULL;
+ char *ConfAutoFileName;
+ char *LockFileName;
+ struct stat st;
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to execute SET/RESET PERSISTENT command"))));
+
+ if (IsTransactionBlock())
+ ereport(ERROR,
+ (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
+ (errmsg("SET/RESET PERSISTENT command cannot run inside a transaction block"))));
+
+ /*
+ * Validate the name and arguments [value1, value2 ... ].
+ */
+ name = setstmt->name;
+
+ switch (setstmt->kind)
+ {
+ case VAR_SET_VALUE:
+ value = ExtractSetVariableArgs(setstmt);
+ break;
+
+ case VAR_SET_DEFAULT:
+ value = NULL;
+ break;
+
+ default:
+ return;
+ }
+
+ record = validate_conf_option(name, value);
+ if (!record)
+ ereport(ERROR,
+ (errmsg("invalid value for parameter \"%s\": \"%s\"", name, value)));
+
+ /* Create the postgresql.auto.conf.lock file */
+ ConfAutoFileName = AbsoluteConfigLocation(AutoConfigFileName, ConfigFileName);
+ LockFileName = AbsoluteConfigLocation(AutoConfigLockFilename, ConfigFileName);
+
+ LWLockAcquire(SetPersistentLock, LW_EXCLUSIVE);
+
+ lockfd = create_conf_lock_file(LockFileName);
+
+ PG_TRY();
+ {
+ if (stat(ConfAutoFileName, &st) != 0)
+ {
+ int fd;
+
+ fd = open(ConfAutoFileName, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("creation of auto conf file failed as it was not exist\"%s\": %m",
+ ConfAutoFileName)));
+ close(fd);
+
+ ereport(NOTICE,
+ (errmsg("Created auto conf file as it was not exist \"%s\"",
+ ConfAutoFileName)));
+ }
+
+ /* open postgresql.auto.conf file */
+ infile = AllocateFile(ConfAutoFileName, "r");
+ if (infile == NULL)
+ ereport(ERROR,
+ (errmsg("failed to open \"postgresql.auto.conf\" file")));
+
+ /* Parse the postgresql.auto.conf file */
+ ParseConfigFp(infile, ConfAutoFileName, 0, LOG, &head_p, &tail_p);
+
+ FreeFile(infile);
+
+ /* replace with new value */
+ replace_auto_config_value(&head_p, &tail_p, ConfAutoFileName, name,
+ value, (record->vartype == PGC_STRING) ? true : false);
+
+ /* Write the New contents to postgresql.auto.conf.lock file */
+ write_auto_conf_file(lockfd, &head_p);
+
+ close(lockfd);
+ lockfd = -1;
+
+ if (rename(LockFileName, ConfAutoFileName) < 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not rename file \"%s\" to \"%s\" : %m",
+ LockFileName, ConfAutoFileName)));
+ }
+ PG_CATCH();
+ {
+ if (lockfd >= 0)
+ close(lockfd);
+
+ unlink(LockFileName);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+
+ LWLockRelease(SetPersistentLock);
+ return;
+ }
+
+
+ /*
* Set a config option to the given value.
*
* See also set_config_option; this is just the wrapper to be called from
***************
*** 6167,6172 **** ExecSetVariableStmt(VariableSetStmt *stmt)
--- 6645,6656 ----
switch (stmt->kind)
{
case VAR_SET_VALUE:
+ if (stmt->is_persistent)
+ {
+ set_config_file(stmt);
+ break;
+ }
+ /* FALLTHROUGH */
case VAR_SET_CURRENT:
(void) set_config_option(stmt->name,
ExtractSetVariableArgs(stmt),
***************
*** 6246,6251 **** ExecSetVariableStmt(VariableSetStmt *stmt)
--- 6730,6741 ----
stmt->name);
break;
case VAR_SET_DEFAULT:
+ if (stmt->is_persistent)
+ {
+ set_config_file(stmt);
+ break;
+ }
+ /* FALLTHROUGH */
case VAR_RESET:
(void) set_config_option(stmt->name,
NULL,
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 581,586 ****
--- 581,593 ----
#include_if_exists = 'exists.conf' # include file only if it exists
#include = 'special.conf' # include file
+ # This includes the default configuration directory included to support
+ # SET PERSISTENT statement.
+ #
+ # WARNING: Any configuration parameter values specified after this line
+ # will override the values set by SET PERSISTENT statement.
+ #include_dir = 'auto.conf.d'
+
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
***************
*** 192,198 **** const char *subdirs[] = {
"base",
"base/1",
"pg_tblspc",
! "pg_stat_tmp"
};
--- 192,199 ----
"base",
"base/1",
"pg_tblspc",
! "pg_stat_tmp",
! "config_dir"
};
***************
*** 1209,1214 **** setup_config(void)
--- 1210,1216 ----
char repltok[MAXPGPATH];
char path[MAXPGPATH];
const char *default_timezone;
+ FILE *autofile;
fputs(_("creating configuration files ... "), stdout);
fflush(stdout);
***************
*** 1291,1301 **** setup_config(void)
--- 1293,1326 ----
conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
}
+ snprintf(repltok, sizeof(repltok), "include_dir = 'config_dir'");
+ conflines = replace_token(conflines, "#include_dir = 'auto.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);
*** 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/storage/lwlock.h
--- b/src/include/storage/lwlock.h
***************
*** 79,84 **** typedef enum LWLockId
--- 79,85 ----
SerializablePredicateLockListLock,
OldSerXidLock,
SyncRepLock,
+ SetPersistentLock,
/* Individual lock IDs end here */
FirstBufMappingLock,
FirstLockMgrLock = FirstBufMappingLock + NUM_BUFFER_PARTITIONS,
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
***************
*** 105,115 **** typedef struct ConfigVariable
--- 105,118 ----
{
char *name;
char *value;
+ bool is_quoted;
char *filename;
int sourceline;
struct ConfigVariable *next;
} ConfigVariable;
+ extern char *AbsoluteConfigLocation(const char *location,
+ const char *calling_file);
extern bool ParseConfigFile(const char *config_file, const char *calling_file,
bool strict, int depth, int elevel,
ConfigVariable **head_p, ConfigVariable **tail_p);
***************
*** 191,196 **** typedef enum
--- 194,204 ----
#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 AutoConfigLockFilename "config_dir/postgresql.auto.conf.lock"
+ #define PGAUTOCONFLOCK "postgresql.auto.conf.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);
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);
!
#endif /* GUC_TABLES_H */
--- 260,265 ----
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, char *value);
#endif /* GUC_TABLES_H */
*** /dev/null
--- b/src/test/regress/expected/persistent.out
***************
*** 0 ****
--- 1,584 ----
+ -- parameter which cannot be set after connection start.
+ set persistent log_connections=on;
+ -- parameter can only be set at during server start.
+ set persistent max_connections To 10;
+ set persistent wal_level = hot_standby;
+ -- parameter can set by the backend
+ set persistent authentication_timeout = 10;
+ set persistent vacuum_cost_delay To 200;
+ ERROR: 200 is outside the valid range for parameter "vacuum_cost_delay" (0 .. 100)
+ set persistent bgwriter_lru_multiplier = 3.2;
+ set persistent full_page_writes = off;
+ set persistent synchronous_commit To off;
+ set persistent synchronous_standby_names = 'standby1, standby2';
+ set persistent seq_page_cost = 0.9;
+ set persistent autovacuum_naptime To 30;
+ set persistent search_path = 'public';
+ set persistent default_tablespace = '';
+ set persistent checkpoint_timeout = 1;
+ ERROR: 1 is outside the valid range for parameter "checkpoint_timeout" (30 .. 3600)
+ set persistent checkpoint_timeout = 3700;
+ ERROR: 3700 is outside the valid range for parameter "checkpoint_timeout" (30 .. 3600)
+ set persistent checkpoint_timeout = 90;
+ set persistent restart_after_crash TO on;
+ show log_connections;
+ log_connections
+ -----------------
+ off
+ (1 row)
+
+ show max_connections;
+ max_connections
+ -----------------
+ 100
+ (1 row)
+
+ show wal_level;
+ wal_level
+ -----------
+ minimal
+ (1 row)
+
+ show authentication_timeout;
+ authentication_timeout
+ ------------------------
+ 1min
+ (1 row)
+
+ show vacuum_cost_delay;
+ vacuum_cost_delay
+ -------------------
+ 0
+ (1 row)
+
+ show bgwriter_lru_multiplier;
+ bgwriter_lru_multiplier
+ -------------------------
+ 2
+ (1 row)
+
+ show full_page_writes;
+ full_page_writes
+ ------------------
+ on
+ (1 row)
+
+ show synchronous_commit;
+ synchronous_commit
+ --------------------
+ on
+ (1 row)
+
+ show synchronous_standby_names;
+ synchronous_standby_names
+ ---------------------------
+
+ (1 row)
+
+ show seq_page_cost;
+ seq_page_cost
+ ---------------
+ 1
+ (1 row)
+
+ show autovacuum_naptime;
+ autovacuum_naptime
+ --------------------
+ 1min
+ (1 row)
+
+ show search_path;
+ search_path
+ ----------------
+ "$user",public
+ (1 row)
+
+ show default_tablespace;
+ default_tablespace
+ --------------------
+
+ (1 row)
+
+ show checkpoint_timeout;
+ checkpoint_timeout
+ --------------------
+ 5min
+ (1 row)
+
+ show restart_after_crash;
+ restart_after_crash
+ ---------------------
+ on
+ (1 row)
+
+ -- reload the new configurations.
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ show log_connections;
+ log_connections
+ -----------------
+ off
+ (1 row)
+
+ show max_connections;
+ max_connections
+ -----------------
+ 100
+ (1 row)
+
+ show wal_level;
+ wal_level
+ -----------
+ minimal
+ (1 row)
+
+ show authentication_timeout;
+ authentication_timeout
+ ------------------------
+ 10s
+ (1 row)
+
+ show vacuum_cost_delay;
+ vacuum_cost_delay
+ -------------------
+ 0
+ (1 row)
+
+ show bgwriter_lru_multiplier;
+ bgwriter_lru_multiplier
+ -------------------------
+ 3.2
+ (1 row)
+
+ show full_page_writes;
+ full_page_writes
+ ------------------
+ off
+ (1 row)
+
+ show synchronous_commit;
+ synchronous_commit
+ --------------------
+ off
+ (1 row)
+
+ show synchronous_standby_names;
+ synchronous_standby_names
+ ---------------------------
+ standby1, standby2
+ (1 row)
+
+ show seq_page_cost;
+ seq_page_cost
+ ---------------
+ 0.9
+ (1 row)
+
+ show autovacuum_naptime;
+ autovacuum_naptime
+ --------------------
+ 30s
+ (1 row)
+
+ show search_path;
+ search_path
+ -------------
+ public
+ (1 row)
+
+ show default_tablespace;
+ default_tablespace
+ --------------------
+
+ (1 row)
+
+ show checkpoint_timeout;
+ checkpoint_timeout
+ --------------------
+ 90s
+ (1 row)
+
+ show restart_after_crash;
+ restart_after_crash
+ ---------------------
+ on
+ (1 row)
+
+ -- reconnect to see the new configurations
+ \c
+ select name, setting from pg_settings where name = 'log_connections';
+ name | setting
+ -----------------+---------
+ log_connections | on
+ (1 row)
+
+ select name, setting from pg_settings where name = 'max_connections';
+ name | setting
+ -----------------+---------
+ max_connections | 100
+ (1 row)
+
+ select name, setting from pg_settings where name = 'wal_level';
+ name | setting
+ -----------+---------
+ wal_level | minimal
+ (1 row)
+
+ select name, setting from pg_settings where name = 'authentication_timeout';
+ name | setting
+ ------------------------+---------
+ authentication_timeout | 10
+ (1 row)
+
+ select name, setting from pg_settings where name = 'vacuum_cost_delay';
+ name | setting
+ -------------------+---------
+ vacuum_cost_delay | 0
+ (1 row)
+
+ select name, setting from pg_settings where name = 'bgwriter_lru_multiplier';
+ name | setting
+ -------------------------+---------
+ bgwriter_lru_multiplier | 3.2
+ (1 row)
+
+ select name, setting from pg_settings where name = 'full_page_writes';
+ name | setting
+ ------------------+---------
+ full_page_writes | off
+ (1 row)
+
+ select name, setting from pg_settings where name = 'synchronous_commit';
+ name | setting
+ --------------------+---------
+ synchronous_commit | off
+ (1 row)
+
+ select name, setting from pg_settings where name = 'synchronous_standby_names';
+ name | setting
+ ---------------------------+--------------------
+ synchronous_standby_names | standby1, standby2
+ (1 row)
+
+ select name, setting from pg_settings where name = 'seq_page_cost';
+ name | setting
+ ---------------+---------
+ seq_page_cost | 0.9
+ (1 row)
+
+ select name, setting from pg_settings where name = 'autovacuum_naptime';
+ name | setting
+ --------------------+---------
+ autovacuum_naptime | 30
+ (1 row)
+
+ select name, setting from pg_settings where name = 'search_path';
+ name | setting
+ -------------+---------
+ search_path | public
+ (1 row)
+
+ select name, setting from pg_settings where name = 'default_tablespace';
+ name | setting
+ --------------------+---------
+ default_tablespace |
+ (1 row)
+
+ select name, setting from pg_settings where name = 'checkpoint_timeout';
+ name | setting
+ --------------------+---------
+ checkpoint_timeout | 90
+ (1 row)
+
+ select name, setting from pg_settings where name = 'restart_after_crash';
+ name | setting
+ ---------------------+---------
+ restart_after_crash | on
+ (1 row)
+
+ -- Reset the some of the parameters which are set in above
+ set persistent log_connections = default;
+ set persistent max_connections To default;
+ set persistent authentication_timeout To default;
+ set persistent synchronous_commit = default;
+ set persistent restart_after_crash To default;
+ -- reload the new configurations.
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ select name, setting from pg_settings where name = 'log_connections';
+ name | setting
+ -----------------+---------
+ log_connections | on
+ (1 row)
+
+ select name, setting from pg_settings where name = 'max_connections';
+ name | setting
+ -----------------+---------
+ max_connections | 100
+ (1 row)
+
+ select name, setting from pg_settings where name = 'authentication_timeout';
+ name | setting
+ ------------------------+---------
+ authentication_timeout | 60
+ (1 row)
+
+ select name, setting from pg_settings where name = 'seq_page_cost';
+ name | setting
+ ---------------+---------
+ seq_page_cost | 0.9
+ (1 row)
+
+ select name, setting from pg_settings where name = 'restart_after_crash';
+ name | setting
+ ---------------------+---------
+ restart_after_crash | on
+ (1 row)
+
+ -- reconnect to see the new configurations
+ \c
+ show log_connections;
+ log_connections
+ -----------------
+ off
+ (1 row)
+
+ show max_connections;
+ max_connections
+ -----------------
+ 100
+ (1 row)
+
+ show authentication_timeout;
+ authentication_timeout
+ ------------------------
+ 1min
+ (1 row)
+
+ show seq_page_cost;
+ seq_page_cost
+ ---------------
+ 0.9
+ (1 row)
+
+ show restart_after_crash;
+ restart_after_crash
+ ---------------------
+ on
+ (1 row)
+
+ -- set the parameters again which are reset above.
+ set persistent log_connections To yes;
+ set persistent max_connections = 50;
+ set persistent authentication_timeout = 20;
+ set persistent synchronous_commit To off;
+ set persistent restart_after_crash To yes;
+ -- reload the new configurations.
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ show log_connections;
+ log_connections
+ -----------------
+ off
+ (1 row)
+
+ show max_connections;
+ max_connections
+ -----------------
+ 100
+ (1 row)
+
+ show authentication_timeout;
+ authentication_timeout
+ ------------------------
+ 20s
+ (1 row)
+
+ show seq_page_cost;
+ seq_page_cost
+ ---------------
+ 0.9
+ (1 row)
+
+ show restart_after_crash;
+ restart_after_crash
+ ---------------------
+ on
+ (1 row)
+
+ -- reconnect to see the new configurations
+ \c
+ show log_connections;
+ log_connections
+ -----------------
+ on
+ (1 row)
+
+ show max_connections;
+ max_connections
+ -----------------
+ 100
+ (1 row)
+
+ show authentication_timeout;
+ authentication_timeout
+ ------------------------
+ 20s
+ (1 row)
+
+ show seq_page_cost;
+ seq_page_cost
+ ---------------
+ 0.9
+ (1 row)
+
+ show restart_after_crash;
+ restart_after_crash
+ ---------------------
+ on
+ (1 row)
+
+ -- set a configuration param inside a function
+ create or replace function persistent_func() returns integer as
+ $$
+ begin
+ set persistent enable_hashagg=off;
+ return 1;
+ end;
+ $$ Language plpgsql;
+ select persistent_func();
+ persistent_func
+ -----------------
+ 1
+ (1 row)
+
+ show enable_hashagg;
+ enable_hashagg
+ ----------------
+ on
+ (1 row)
+
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ show enable_hashagg;
+ enable_hashagg
+ ----------------
+ off
+ (1 row)
+
+ create or replace function persistent_func() returns integer as
+ $$
+ begin
+ set persistent enable_hashagg=default;
+ return 1;
+ end;
+ $$ Language plpgsql;
+ select persistent_func();
+ persistent_func
+ -----------------
+ 1
+ (1 row)
+
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ show enable_hashagg;
+ enable_hashagg
+ ----------------
+ on
+ (1 row)
+
+ Drop function persistent_func();
+ -- Reset all parameters which are set at above.
+ set persistent log_connections To default;
+ set persistent max_connections = default;
+ set persistent wal_level To default;
+ set persistent authentication_timeout To default;
+ set persistent vacuum_cost_delay = default;
+ set persistent bgwriter_lru_multiplier To default;
+ set persistent full_page_writes To default;
+ set persistent synchronous_commit = default;
+ set persistent synchronous_standby_names To default;
+ set persistent seq_page_cost To default;
+ set persistent autovacuum_naptime = default;
+ set persistent search_path To default;
+ set persistent default_tablespace To default;
+ set persistent checkpoint_timeout To default;
+ set persistent restart_after_crash = default;
+ select pg_reload_conf();
+ pg_reload_conf
+ ----------------
+ t
+ (1 row)
+
+ select pg_sleep(1);
+ pg_sleep
+ ----------
+
+ (1 row)
+
+ -- Normal user tries to set
+ create user test password 'test';
+ SET SESSION AUTHORIZATION test;
+ set persistent enable_seqscan=off;
+ ERROR: must be superuser to execute SET/RESET PERSISTENT command
+ \c -
+ drop user test;
+ -- In a transaction block tries to set
+ start transaction;
+ set persistent enable_hashagg=off;
+ ERROR: SET/RESET PERSISTENT command cannot run inside a transaction block
+ commit;
+ start transaction;
+ set persistent enable_hashagg=default;
+ ERROR: SET/RESET PERSISTENT command cannot run inside a transaction block
+ commit;
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
***************
*** 108,111 **** test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combo
test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
# run stats by itself because its delay may be insufficient under heavy load
! test: stats
--- 108,114 ----
test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
# run stats by itself because its delay may be insufficient under heavy load
! test: stats
!
! # run persistent by itself because it modifies the configuration parameters
! test: persistent
*** a/src/test/regress/serial_schedule
--- b/src/test/regress/serial_schedule
***************
*** 135,137 **** test: largeobject
--- 135,138 ----
test: with
test: xml
test: stats
+ test: persistent
*** /dev/null
--- b/src/test/regress/sql/persistent.sql
***************
*** 0 ****
--- 1,215 ----
+ -- parameter which cannot be set after connection start.
+ set persistent log_connections=on;
+
+ -- parameter can only be set at during server start.
+ set persistent max_connections To 10;
+ set persistent wal_level = hot_standby;
+
+ -- parameter can set by the backend
+ set persistent authentication_timeout = 10;
+ set persistent vacuum_cost_delay To 200;
+ set persistent bgwriter_lru_multiplier = 3.2;
+ set persistent full_page_writes = off;
+ set persistent synchronous_commit To off;
+ set persistent synchronous_standby_names = 'standby1, standby2';
+ set persistent seq_page_cost = 0.9;
+ set persistent autovacuum_naptime To 30;
+ set persistent search_path = 'public';
+ set persistent default_tablespace = '';
+ set persistent checkpoint_timeout = 1;
+ set persistent checkpoint_timeout = 3700;
+ set persistent checkpoint_timeout = 90;
+ set persistent restart_after_crash TO on;
+
+
+ show log_connections;
+
+ show max_connections;
+ show wal_level;
+
+ show authentication_timeout;
+ show vacuum_cost_delay;
+ show bgwriter_lru_multiplier;
+ show full_page_writes;
+ show synchronous_commit;
+ show synchronous_standby_names;
+ show seq_page_cost;
+ show autovacuum_naptime;
+ show search_path;
+ show default_tablespace;
+ show checkpoint_timeout;
+ show restart_after_crash;
+
+ -- reload the new configurations.
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+ show log_connections;
+
+ show max_connections;
+ show wal_level;
+
+ show authentication_timeout;
+ show vacuum_cost_delay;
+ show bgwriter_lru_multiplier;
+ show full_page_writes;
+ show synchronous_commit;
+ show synchronous_standby_names;
+ show seq_page_cost;
+ show autovacuum_naptime;
+ show search_path;
+ show default_tablespace;
+ show checkpoint_timeout;
+ show restart_after_crash;
+
+
+ -- reconnect to see the new configurations
+ \c
+
+ select name, setting from pg_settings where name = 'log_connections';
+
+ select name, setting from pg_settings where name = 'max_connections';
+ select name, setting from pg_settings where name = 'wal_level';
+
+ select name, setting from pg_settings where name = 'authentication_timeout';
+ select name, setting from pg_settings where name = 'vacuum_cost_delay';
+ select name, setting from pg_settings where name = 'bgwriter_lru_multiplier';
+ select name, setting from pg_settings where name = 'full_page_writes';
+ select name, setting from pg_settings where name = 'synchronous_commit';
+ select name, setting from pg_settings where name = 'synchronous_standby_names';
+ select name, setting from pg_settings where name = 'seq_page_cost';
+ select name, setting from pg_settings where name = 'autovacuum_naptime';
+ select name, setting from pg_settings where name = 'search_path';
+ select name, setting from pg_settings where name = 'default_tablespace';
+ select name, setting from pg_settings where name = 'checkpoint_timeout';
+ select name, setting from pg_settings where name = 'restart_after_crash';
+
+ -- Reset the some of the parameters which are set in above
+ set persistent log_connections = default;
+
+ set persistent max_connections To default;
+
+ set persistent authentication_timeout To default;
+ set persistent synchronous_commit = default;
+ set persistent restart_after_crash To default;
+
+ -- reload the new configurations.
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+ select name, setting from pg_settings where name = 'log_connections';
+ select name, setting from pg_settings where name = 'max_connections';
+ select name, setting from pg_settings where name = 'authentication_timeout';
+ select name, setting from pg_settings where name = 'seq_page_cost';
+ select name, setting from pg_settings where name = 'restart_after_crash';
+
+ -- reconnect to see the new configurations
+ \c
+
+ show log_connections;
+ show max_connections;
+ show authentication_timeout;
+ show seq_page_cost;
+ show restart_after_crash;
+
+ -- set the parameters again which are reset above.
+ set persistent log_connections To yes;
+
+ set persistent max_connections = 50;
+
+ set persistent authentication_timeout = 20;
+ set persistent synchronous_commit To off;
+ set persistent restart_after_crash To yes;
+
+ -- reload the new configurations.
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+ show log_connections;
+ show max_connections;
+ show authentication_timeout;
+ show seq_page_cost;
+ show restart_after_crash;
+
+ -- reconnect to see the new configurations
+ \c
+ show log_connections;
+ show max_connections;
+ show authentication_timeout;
+ show seq_page_cost;
+ show restart_after_crash;
+
+ -- set a configuration param inside a function
+ create or replace function persistent_func() returns integer as
+ $$
+ begin
+ set persistent enable_hashagg=off;
+ return 1;
+ end;
+ $$ Language plpgsql;
+
+ select persistent_func();
+
+ show enable_hashagg;
+
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+ show enable_hashagg;
+
+ create or replace function persistent_func() returns integer as
+ $$
+ begin
+ set persistent enable_hashagg=default;
+ return 1;
+ end;
+ $$ Language plpgsql;
+
+ select persistent_func();
+
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+ show enable_hashagg;
+
+ Drop function persistent_func();
+
+ -- Reset all parameters which are set at above.
+ set persistent log_connections To default;
+
+ set persistent max_connections = default;
+ set persistent wal_level To default;
+
+ set persistent authentication_timeout To default;
+ set persistent vacuum_cost_delay = default;
+ set persistent bgwriter_lru_multiplier To default;
+ set persistent full_page_writes To default;
+ set persistent synchronous_commit = default;
+ set persistent synchronous_standby_names To default;
+ set persistent seq_page_cost To default;
+ set persistent autovacuum_naptime = default;
+ set persistent search_path To default;
+ set persistent default_tablespace To default;
+ set persistent checkpoint_timeout To default;
+ set persistent restart_after_crash = default;
+
+ select pg_reload_conf();
+ select pg_sleep(1);
+
+
+ -- Normal user tries to set
+ create user test password 'test';
+ SET SESSION AUTHORIZATION test;
+ set persistent enable_seqscan=off;
+ \c -
+ drop user test;
+
+ -- In a transaction block tries to set
+ start transaction;
+ set persistent enable_hashagg=off;
+ commit;
+
+ start transaction;
+ set persistent enable_hashagg=default;
+ commit;
+