diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml
index a7e81d22d9..76a4ac014a 100644
--- a/doc/src/sgml/ref/alter_database.sgml
+++ b/doc/src/sgml/ref/alter_database.sgml
@@ -1,5 +1,5 @@
@@ -28,10 +28,9 @@ ALTER DATABASE name RESET ALTER DATABASE is used to change the session
default of a run-time configuration variable for a
PostgreSQL database. Whenever a new
- session is subsequently started in that database, SET
- variable TO
- value is effectively executed
- before the start of the session. The database-specific default
+ session is subsequently started in that database, the specified
+ value becomes the session default value.
+ The database-specific default
overrides whatever setting is present in postgresql.conf>
or has been received from the postmaster.
@@ -64,7 +63,8 @@ ALTER DATABASE name RESET value is DEFAULT
or, equivalently, RESET is used, the
- database-specific variable setting is removed and the default
+ database-specific variable setting is removed and the system-wide
+ default
setting will be inherited in new sessions. Use RESET
ALL to clear all settings.
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index d8461c4f4f..3cc82371aa 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -1,5 +1,5 @@
@@ -48,14 +48,13 @@ ALTER USER username RESET
- The second and the third variant change a user's session default of
+ The second and the third variant change a user's session default for
a specified configuration variable. Whenever the user subsequently
- starts a new session, SET
- variable TO
- value is effectively executed
- before the start of the session. Ordinary users can change their
- own session defaults. Superusers can change anyone's session
- defaults.
+ starts a new session, the specified value becomes the session default,
+ overriding whatever setting is present in postgresql.conf>
+ or has been received from the postmaster.
+ Ordinary users can change their own session defaults.
+ Superusers can change anyone's session defaults.
@@ -135,12 +134,12 @@ ALTER USER username RESET value
- Set this user's session default of the specified configuration
+ Set this user's session default for the specified configuration
variable to the given value. If
value is DEFAULT
or, equivalently, RESET is used, the
user-specific variable setting is removed and the user will
- inherit the default setting in new sessions. Use
+ inherit the system-wide default setting in new sessions. Use
RESET ALL to clear all settings.
diff --git a/doc/src/sgml/ref/reset.sgml b/doc/src/sgml/ref/reset.sgml
index 69c1f861ee..9f78d9df6c 100644
--- a/doc/src/sgml/ref/reset.sgml
+++ b/doc/src/sgml/ref/reset.sgml
@@ -1,5 +1,5 @@
@@ -37,7 +37,7 @@ RESET ALL
ALL
- Resets all run-time parameters to default values.
+ Resets all settable run-time parameters to default values.
@@ -53,11 +53,18 @@ RESET ALL
RESET restores run-time parameters to their
default values. Refer to
- for details. RESET is an alternate form for
+ for details. RESET is an alternate spelling for
SET variable TO DEFAULT
+
+ The default value is defined as the value that the variable would
+ have had, had no SET> ever been issued for it in the
+ current session. The actual source of this value might be a
+ compiled-in default, the postmaster's configuration file or command-line
+ switches, or per-database or per-user default settings. See the
+ Administrator's Guide for details.
diff --git a/doc/src/sgml/ref/set.sgml b/doc/src/sgml/ref/set.sgml
index 0dd4c44db1..f54f70c197 100644
--- a/doc/src/sgml/ref/set.sgml
+++ b/doc/src/sgml/ref/set.sgml
@@ -1,5 +1,5 @@
@@ -14,14 +14,40 @@ PostgreSQL documentation
-SET variable { TO | = } { value | 'value' | DEFAULT }
-SET TIME ZONE { 'timezone' | LOCAL | DEFAULT }
+SET [ SESSION | LOCAL ] variable { TO | = } { value | 'value' | DEFAULT }
+SET [ SESSION | LOCAL ] TIME ZONE { timezone | LOCAL | DEFAULT }
Inputs
+
+
+
+
+
+ Specifies that the command takes effect for the current session.
+ (This is the default if neither
+
+
+
+
+
+
+
+ Specifies that the command takes effect for only the current
+ transaction. After COMMIT> or ROLLBACK>,
+ the session-level setting takes effect again. Note that
+ SET LOCAL> will appear to have no effect if it's
+ executed outside a BEGIN> block, since the transaction
+ will end immediately.
+
+
+
+
variable
@@ -30,6 +56,7 @@ SET TIME ZONE { 'timezone' | LOCAL
+
value
@@ -49,34 +76,49 @@ SET TIME ZONE { 'timezone' | LOCAL
Description
+
The SET command changes run-time configuration
- parameters. The following parameters can be altered:
+ parameters. Many of the run-time parameters listed in the
+ Administrator's Guide can be changed on-the-fly
+ with SET. (But some require superuser privileges
+ to change, and others cannot be changed after server or session start.)
+ Note that SET only affects the value used by the
+ current session.
+
+
+
+ If SET or SET SESSION is issued
+ within a transaction that is later aborted, the effects of the
+ SET command disappear when the transaction is rolled
+ back. (This behavior represents a change from
+ PostgreSQL versions prior to 7.3, where
+ the effects of SET would not roll back after a later
+ error.) Once the surrounding transaction is committed, the effects
+ will persist until the end of the session, unless overridden by another
+ SET.
+
+
+
+ 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
+ a single transaction: the SET LOCAL value will be
+ seen until the end of the transaction, but afterwards (if the transaction
+ is committed) the SET value will take effect.
+
+
+
+ Here are additional details about a few of the parameters that can be set:
-
- CLIENT_ENCODING
- NAMES
-
-
- Sets the multibyte client encoding. The specified encoding
- must be supported by the backend.
-
-
-
- This option is only available if
- PostgreSQL is build with multibyte
- support.
-
-
-
DATESTYLE
Choose the date/time representation style. Two separate
- settings are made: the default date/time output and the
+ settings are involved: the default date/time output and the
interpretation of ambiguous input.
@@ -158,22 +200,6 @@ SET TIME ZONE { 'timezone' | LOCAL
(substyles), or one from each separated by a comma.
-
- Date format initialization may be done by:
-
-
- Setting the PGDATESTYLE environment variable.
- If PGDATESTYLE is set in the frontend environment of a client
- based on libpq, libpq will automatically set DATESTYLE to the
- value of PGDATESTYLE during connection start-up.
-
-
- Running postmaster using the option to
- set dates to the European convention.
-
-
-
-
SET DATESTYLE affects interpretation of
input and provides several standard output formats. For
@@ -182,6 +208,41 @@ SET TIME ZONE { 'timezone' | LOCAL
the to_char family of
functions.
+
+
+ There are several now-deprecated means for setting the datestyle
+ in addition to the normal methods of setting it via SET> or
+ a configuration-file entry:
+
+
+ Setting the postmaster's PGDATESTYLE environment
+ variable. (This will be overridden by any of the other methods.)
+
+
+ Running postmaster using the option to
+ select the European conventions.
+ (This overrides environment variables and configuration-file
+ entries.)
+
+
+ Setting the client's PGDATESTYLE environment variable.
+ If PGDATESTYLE is set in the frontend environment of a client
+ based on libpq, libpq will automatically set DATESTYLE to the
+ value of PGDATESTYLE during connection start-up. This is
+ equivalent to a manually issued SET>.
+
+
+
+
+
+
+
+
+ NAMES
+
+
+ SET NAMES> is an alias for SET CLIENT_ENCODING>.
+
@@ -199,23 +260,22 @@ SET TIME ZONE { 'timezone' | LOCAL
The value for the seed to be used by the
random function. Allowed
values are floating-point numbers between 0 and 1, which
- are then multiplied by 231>-1. This product will
- silently overflow if a number outside the range is used.
-
-
-
- The seed can also be set by invoking the
- setseed SQL function:
-
-
-SELECT setseed(value);
-
+ are then multiplied by 231>-1.
+
+ The seed can also be set by invoking the
+ setseed SQL function:
+
+
+SELECT setseed(value);
+
+
+
@@ -223,13 +283,9 @@ SELECT setseed(value);
SERVER_ENCODING
- Sets the multibyte server encoding.
-
-
-
- This option is only available if
- PostgreSQL was built with multibyte
- support.
+ Shows the server-side multibyte encoding. (At present, this
+ parameter can be shown but not set, because the encoding is
+ determined at initdb time.)
@@ -241,18 +297,18 @@ SELECT setseed(value);
Sets the default time zone for your session. Arguments can be
an SQL time interval constant, an integer or double precision
- constant, or a string representing a time zone supported by
- the host operating system.
+ constant, or a string representing a time zone name recognized
+ by the host operating system.
- The possible values for time zone depends on your operating
+ The available time zone names depend on your operating
system. For example, on Linux
/usr/share/zoneinfo contains the database
of time zones.
- Here are some valid values for time zone:
+ Here are some typical values for time zone names:
@@ -279,6 +335,14 @@ SELECT setseed(value);
+
+
+
+
+ In addition to time zone names, PostgreSQL
+ accepts these other methods of specifying a time zone:
+
+
7
@@ -310,7 +374,7 @@ SELECT setseed(value);
- If an invalid time zone is specified, the time zone
+ If an invalid time zone name is specified, the time zone
becomes GMT (on most systems anyway).
@@ -324,14 +388,9 @@ SELECT setseed(value);
-
- An extended list of other run-time parameters can be found in the
- Administrator's Guide.
-
-
Use to show the
- current setting of a parameters.
+ current setting of a parameter.
@@ -363,7 +422,7 @@ SELECT setseed(value);
ERROR: permission denied
- You must be a superuser to have access to certain settings.
+ You must be a superuser to alter certain settings.
@@ -394,7 +453,7 @@ SET DATESTYLE TO PostgreSQL,European;
Set the time zone for Berkeley, California, using quotes to
- preserve the uppercase attributes of the time zone specifier (note
+ preserve the uppercase spelling of the time zone name (note
that the date style is PostgreSQL for this
example):
@@ -437,8 +496,8 @@ SELECT CURRENT_TIMESTAMP AS today;
only numeric time zone offsets while
PostgreSQL allows full time zone
specifier strings as well. All other SET
- features are a
- PostgreSQL extension.
+ features are
+ PostgreSQL extensions.
diff --git a/doc/src/sgml/ref/set_session_auth.sgml b/doc/src/sgml/ref/set_session_auth.sgml
index 7cd0d7d1ec..dfb2035700 100644
--- a/doc/src/sgml/ref/set_session_auth.sgml
+++ b/doc/src/sgml/ref/set_session_auth.sgml
@@ -1,4 +1,4 @@
-
+
2001-04-21
@@ -16,8 +16,8 @@
-SET SESSION AUTHORIZATION username
-SET SESSION AUTHORIZATION DEFAULT
+SET [ SESSION | LOCAL ] SESSION AUTHORIZATION username
+SET [ SESSION | LOCAL ] SESSION AUTHORIZATION DEFAULT
RESET SESSION AUTHORIZATION
@@ -51,6 +51,12 @@ RESET SESSION AUTHORIZATION
specifies the authenticated username.
+
+ The
+
The DEFAULT> and RESET> forms reset the session
and current user identifiers to be the originally authenticated user
diff --git a/doc/src/sgml/ref/show.sgml b/doc/src/sgml/ref/show.sgml
index 37e7e85652..b752f86ee6 100644
--- a/doc/src/sgml/ref/show.sgml
+++ b/doc/src/sgml/ref/show.sgml
@@ -1,5 +1,5 @@
@@ -54,7 +54,7 @@ SHOW ALL
SHOW will display the current setting of a
run-time parameter. These variables can be set using the
- SET statement or are determined at server start.
+ SET statement or are determined at session start.
@@ -72,25 +72,6 @@ SHOW ALL
-
-
- ERROR: permission denied
-
-
- You must be a superuser to be allowed to see certain settings.
-
-
-
-
-
- WARNING: Time zone is unknown
-
-
- If the TZ or PGTZ environment
- variable is not set.
-
-
-
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 72157ff271..889f2203f6 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -1,5 +1,5 @@
@@ -24,6 +24,9 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 70131be3a2..78d6dec0aa 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
@@ -488,11 +488,13 @@ psql: could not connect to server: Connection refused
# This is a comment
log_connections = yes
syslog = 2
+search_path = '$user, public'
As you see, options are one per line. The equal sign between name
and value is optional. Whitespace is insignificant and blank lines
are ignored. Hash marks (#
) introduce comments
- anywhere.
+ anywhere. Parameter values that are not simple identifiers or
+ numbers should be single-quoted.
@@ -526,7 +528,7 @@ postmaster -c log_connections=yes -c syslog=2
env PGOPTIONS='-c geqo=off' psql
- (This works for any client application, not just
+ (This works for any libpq-based client application, not just
psql.) Note that this won't work for
options that are fixed when the server is started, such as the port
number.
@@ -539,11 +541,17 @@ env PGOPTIONS='-c geqo=off' psql
=> SET ENABLE_SEQSCAN TO OFF;
See the SQL command language reference for details on the syntax.
+
+
+
Furthermore, it is possible to assign a set of option settings to
a user or a database. Whenever a session is started, the default
settings for the user and database involved are loaded. The
commands ALTER DATABASE and ALTER
- USER, respectively, are used to configure these.
+ USER, respectively, are used to configure these settings.
+ Such per-database settings override anything received from the postmaster
+ or the configuration file, and in turn are overridden by per-user
+ settings.
@@ -1091,6 +1099,34 @@ env PGOPTIONS='-c geqo=off' psql
+
+ CLIENT_ENCODING (string)
+ character set encoding>>
+
+
+ Sets the client-side encoding for multibyte character sets.
+ The default is to use the database encoding.
+
+
+ This option is only available if
+ PostgreSQL was built with multibyte
+ support.
+
+
+
+
+
+ DATESTYLE (string)
+ date style>>
+
+
+ Sets the display format for dates, as well as the rules for
+ interpreting ambiguous input dates.
+ The default is ISO, US>.
+
+
+
+
deadlock
@@ -1586,6 +1622,18 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
+
+ TIMEZONE (string)
+ time zone>>
+
+
+ Sets the time zone for displaying and interpreting timestamps.
+ The default is to use whatever the system environment
+ specifies as the timezone.
+
+
+
+
TRANSFORM_NULL_EQUALS (boolean)
IS NULL>>
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index ca66b0afaf..d6176ec5c4 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.120 2002/04/01 03:34:25 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.121 2002/05/17 01:19:16 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -173,6 +173,7 @@
#include "storage/proc.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
+#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/portal.h"
@@ -1002,6 +1003,7 @@ CommitTransaction(void)
RelationPurgeLocalRelation(true);
smgrDoPendingDeletes(true);
+ AtEOXact_GUC(true);
AtEOXact_SPI();
AtEOXact_gist();
AtEOXact_hash();
@@ -1104,6 +1106,7 @@ AbortTransaction(void)
RelationPurgeLocalRelation(false);
smgrDoPendingDeletes(false);
+ AtEOXact_GUC(false);
AtEOXact_SPI();
AtEOXact_gist();
AtEOXact_hash();
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index eca4a5de5f..77ad566ba8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.94 2002/05/09 13:30:24 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.95 2002/05/17 01:19:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3272,31 +3272,10 @@ xlog_outrec(char *buf, XLogRecord *record)
/*
- * GUC support routines
+ * GUC support
*/
-
-bool
-check_xlog_sync_method(const char *method)
-{
- if (strcasecmp(method, "fsync") == 0)
- return true;
-#ifdef HAVE_FDATASYNC
- if (strcasecmp(method, "fdatasync") == 0)
- return true;
-#endif
-#ifdef OPEN_SYNC_FLAG
- if (strcasecmp(method, "open_sync") == 0)
- return true;
-#endif
-#ifdef OPEN_DATASYNC_FLAG
- if (strcasecmp(method, "open_datasync") == 0)
- return true;
-#endif
- return false;
-}
-
-void
-assign_xlog_sync_method(const char *method)
+const char *
+assign_xlog_sync_method(const char *method, bool doit, bool interactive)
{
int new_sync_method;
int new_sync_bit;
@@ -3329,12 +3308,12 @@ assign_xlog_sync_method(const char *method)
#endif
else
{
- /* Can't get here unless guc.c screwed up */
- elog(ERROR, "bogus wal_sync_method %s", method);
- new_sync_method = 0; /* keep compiler quiet */
- new_sync_bit = 0;
+ return NULL;
}
+ if (!doit)
+ return method;
+
if (sync_method != new_sync_method || open_sync_bit != new_sync_bit)
{
/*
@@ -3359,6 +3338,8 @@ assign_xlog_sync_method(const char *method)
sync_method = new_sync_method;
open_sync_bit = new_sync_bit;
}
+
+ return method;
}
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 51f432b1a0..1a13786a04 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.128 2002/05/05 00:03:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.129 2002/05/17 01:19:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -249,7 +249,7 @@ BootstrapMain(int argc, char *argv[])
dbName = NULL;
if (!IsUnderPostmaster)
{
- ResetAllOptions(true);
+ InitializeGUCOptions();
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA
* variable */
}
@@ -263,12 +263,13 @@ BootstrapMain(int argc, char *argv[])
break;
case 'd':
{
- /* Turn on debugging for the postmaster. */
+ /* Turn on debugging for the bootstrap process. */
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
sprintf(debugstr, "debug%s", optarg);
- /* We use PGC_S_SESSION because we will reset in backend */
- SetConfigOption("server_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV);
- SetConfigOption("client_min_messages", debugstr, PGC_POSTMASTER, PGC_S_ARGV);
+ SetConfigOption("server_min_messages", debugstr,
+ PGC_POSTMASTER, PGC_S_ARGV);
+ SetConfigOption("client_min_messages", debugstr,
+ PGC_POSTMASTER, PGC_S_ARGV);
pfree(debugstr);
break;
}
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 9e5002e37f..92c9306f18 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.19 2002/05/12 20:10:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.20 2002/05/17 01:19:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1739,16 +1739,16 @@ RemoveTempRelationsCallback(void)
* Routines for handling the GUC variable 'search_path'.
*/
-/* parse_hook: is proposed value valid? */
-bool
-check_search_path(const char *proposed)
+/* assign_hook: validate new search_path, do extra actions as needed */
+const char *
+assign_search_path(const char *newval, bool doit, bool interactive)
{
char *rawname;
List *namelist;
List *l;
/* Need a modifiable copy of string */
- rawname = pstrdup(proposed);
+ rawname = pstrdup(newval);
/* Parse string into list of identifiers */
if (!SplitIdentifierString(rawname, ',', &namelist))
@@ -1756,59 +1756,45 @@ check_search_path(const char *proposed)
/* syntax error in name list */
pfree(rawname);
freeList(namelist);
- return false;
+ return NULL;
}
/*
* If we aren't inside a transaction, we cannot do database access so
* cannot verify the individual names. Must accept the list on faith.
- * (This case can happen, for example, when the postmaster reads a
- * search_path setting from postgresql.conf.)
*/
- if (!IsTransactionState())
+ if (interactive && IsTransactionState())
{
- pfree(rawname);
- freeList(namelist);
- return true;
- }
-
- /*
- * Verify that all the names are either valid namespace names or "$user".
- * We do not require $user to correspond to a valid namespace.
- * We do not check for USAGE rights, either; should we?
- */
- foreach(l, namelist)
- {
- char *curname = (char *) lfirst(l);
-
- if (strcmp(curname, "$user") == 0)
- continue;
- if (!SearchSysCacheExists(NAMESPACENAME,
- CStringGetDatum(curname),
- 0, 0, 0))
+ /*
+ * Verify that all the names are either valid namespace names or
+ * "$user". We do not require $user to correspond to a valid
+ * namespace. We do not check for USAGE rights, either; should we?
+ */
+ foreach(l, namelist)
{
- pfree(rawname);
- freeList(namelist);
- return false;
+ char *curname = (char *) lfirst(l);
+
+ if (strcmp(curname, "$user") == 0)
+ continue;
+ if (!SearchSysCacheExists(NAMESPACENAME,
+ CStringGetDatum(curname),
+ 0, 0, 0))
+ elog(ERROR, "Namespace \"%s\" does not exist", curname);
}
}
pfree(rawname);
freeList(namelist);
- return true;
-}
-
-/* assign_hook: do extra actions needed when assigning to search_path */
-void
-assign_search_path(const char *newval)
-{
/*
* We mark the path as needing recomputation, but don't do anything until
* it's needed. This avoids trying to do database access during GUC
* initialization.
*/
- namespaceSearchPathValid = false;
+ if (doit)
+ namespaceSearchPathValid = false;
+
+ return newval;
}
/*
@@ -1844,6 +1830,8 @@ InitializeSearchPath(void)
CacheRegisterSyscacheCallback(NAMESPACEOID,
NamespaceCallback,
(Datum) 0);
+ /* Force search path to be recomputed on next use */
+ namespaceSearchPathValid = false;
}
}
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 41f122767a..bb53ad8b3b 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.88 2002/04/27 21:24:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.89 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -458,9 +458,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
char repl_null[Natts_pg_database];
char repl_repl[Natts_pg_database];
- valuestr = (stmt->value
- ? ((A_Const *) lfirst(stmt->value))->val.val.str
- : NULL);
+ valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
@@ -477,7 +475,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
MemSet(repl_repl, ' ', sizeof(repl_repl));
repl_repl[Anum_pg_database_datconfig-1] = 'r';
- if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL)
+ if (strcmp(stmt->variable, "all")==0 && valuestr == NULL)
{
/* RESET ALL */
repl_null[Anum_pg_database_datconfig-1] = 'n';
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 405a7ceaa2..5398d718b6 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.100 2002/04/28 00:36:38 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.101 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -851,9 +851,7 @@ AlterUserSet(AlterUserSetStmt *stmt)
char repl_repl[Natts_pg_shadow];
int i;
- valuestr = (stmt->value
- ? ((A_Const *) lfirst(stmt->value))->val.val.str
- : NULL);
+ valuestr = flatten_set_variable_args(stmt->variable, stmt->value);
/*
* RowExclusiveLock is sufficient, because we don't need to update
@@ -874,7 +872,7 @@ AlterUserSet(AlterUserSetStmt *stmt)
repl_repl[i] = ' ';
repl_repl[Anum_pg_shadow_useconfig-1] = 'r';
- if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL)
+ if (strcmp(stmt->variable, "all")==0 && valuestr == NULL)
/* RESET ALL */
repl_null[Anum_pg_shadow_useconfig-1] = 'n';
else
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index de42538bd6..03d7a66457 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* variable.c
- * Routines for handling of 'SET var TO',
- * 'SHOW var' and 'RESET var' statements.
+ * Routines for handling specialized SET variables.
+ *
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.66 2002/05/06 19:47:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.67 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,15 +21,11 @@
#include "access/xact.h"
#include "catalog/pg_shadow.h"
-#include "catalog/pg_type.h"
#include "commands/variable.h"
#include "miscadmin.h"
-#include "optimizer/cost.h"
-#include "optimizer/paths.h"
-#include "parser/parse_type.h"
#include "utils/builtins.h"
-#include "utils/date.h"
#include "utils/guc.h"
+#include "utils/syscache.h"
#include "utils/tqual.h"
#ifdef MULTIBYTE
@@ -41,470 +37,364 @@
#endif
-static bool show_datestyle(void);
-static bool reset_datestyle(void);
-static bool parse_datestyle(List *);
-static bool show_timezone(void);
-static bool reset_timezone(void);
-static bool parse_timezone(List *);
-
-static bool show_XactIsoLevel(void);
-static bool reset_XactIsoLevel(void);
-static bool parse_XactIsoLevel(List *);
-static bool show_random_seed(void);
-static bool reset_random_seed(void);
-static bool parse_random_seed(List *);
-
-static bool show_client_encoding(void);
-static bool reset_client_encoding(void);
-static bool parse_client_encoding(List *);
-static bool show_server_encoding(void);
-static bool reset_server_encoding(void);
-static bool parse_server_encoding(List *);
-
-
-/*
- * get_token
- * Obtain the next item in a comma-separated list of items,
- * where each item can be either "word" or "word=word".
- * The "word=word" form is only accepted if 'val' is not NULL.
- * Words are any sequences not containing whitespace, ',', or '='.
- * Whitespace can appear between the words and punctuation.
- *
- * 'tok': receives a pointer to first word of item, or NULL if none.
- * 'val': if not NULL, receives a pointer to second word, or NULL if none.
- * 'str': start of input string.
- *
- * Returns NULL if input string contained no more words, else pointer
- * to just past this item, which can be used as 'str' for next call.
- * (If this is the last item, returned pointer will point at a null char,
- * so caller can alternatively check for that instead of calling again.)
- *
- * NB: input string is destructively modified by placing null characters
- * at ends of words!
- *
- * A former version of this code avoided modifying the input string by
- * returning palloc'd copies of the words. However, we want to use this
- * code early in backend startup to parse the PGDATESTYLE environment var,
- * and palloc/pfree aren't initialized at that point. Cleanest answer
- * seems to be to palloc in SetPGVariable() so that we can treat the string
- * as modifiable here.
- */
-static char *
-get_token(char **tok, char **val, char *str)
-{
- char ch;
-
- *tok = NULL;
- if (val != NULL)
- *val = NULL;
-
- if (!str || *str == '\0')
- return NULL;
-
- /* skip leading white space */
- while (isspace((unsigned char) *str))
- str++;
-
- /* end of string? then return NULL */
- if (*str == '\0')
- return NULL;
-
- if (*str == ',' || *str == '=')
- elog(ERROR, "Syntax error near \"%s\": empty setting", str);
-
- /* OK, at beginning of non-empty item */
- *tok = str;
-
- /* Advance to end of word */
- while (*str && !isspace((unsigned char) *str) &&
- *str != ',' && *str != '=')
- str++;
-
- /* Terminate word string for caller */
- ch = *str;
- *str = '\0';
-
- /* Skip any whitespace */
- while (isspace((unsigned char) ch))
- ch = *(++str);
-
- /* end of string? */
- if (ch == '\0')
- return str;
- /* delimiter? */
- if (ch == ',')
- return ++str;
-
- /* Had better be '=', and caller must be expecting it */
- if (val == NULL || ch != '=')
- elog(ERROR, "Syntax error near \"%s\"", str);
-
- /* '=': get the value */
- str++;
-
- /* skip whitespace after '=' */
- while (isspace((unsigned char) *str))
- str++;
-
- if (*str == ',' || *str == '\0')
- elog(ERROR, "Syntax error near \"=%s\"", str);
-
- /* OK, at beginning of non-empty value */
- *val = str;
-
- /* Advance to end of word */
- while (*str && !isspace((unsigned char) *str) && *str != ',')
- str++;
-
- /* Terminate word string for caller */
- ch = *str;
- *str = '\0';
-
- /* Skip any whitespace */
- while (isspace((unsigned char) ch))
- ch = *(++str);
-
- /* end of string? */
- if (ch == '\0')
- return str;
- /* delimiter? */
- if (ch == ',')
- return ++str;
-
- elog(ERROR, "Syntax error near \"%s\"", str);
-
- return str;
-}
-
-
/*
* DATESTYLE
- *
- * NOTE: set_default_datestyle() is called during backend startup to check
- * if the PGDATESTYLE environment variable is set. We want the env var
- * to determine the value that "RESET DateStyle" will reset to!
*/
-/* These get initialized from the "master" values in init/globals.c */
-static int DefaultDateStyle;
-static bool DefaultEuroDates;
-
-static bool
-parse_datestyle_internal(char *value)
+/*
+ * assign_datestyle: GUC assign_hook for datestyle
+ */
+const char *
+assign_datestyle(const char *value, bool doit, bool interactive)
{
- char *tok;
+ int newDateStyle = DateStyle;
+ bool newEuroDates = EuroDates;
+ bool ok = true;
int dcnt = 0,
ecnt = 0;
+ char *rawstring;
+ char *result;
+ List *elemlist;
+ List *l;
- if (value == NULL)
- return reset_datestyle();
+ /* Need a modifiable copy of string */
+ rawstring = pstrdup(value);
- while ((value = get_token(&tok, NULL, value)) != 0)
+ /* Parse string into list of identifiers */
+ if (!SplitIdentifierString(rawstring, ',', &elemlist))
{
+ /* syntax error in list */
+ pfree(rawstring);
+ freeList(elemlist);
+ if (interactive)
+ elog(ERROR, "SET DATESTYLE: invalid list syntax");
+ return NULL;
+ }
+
+ foreach(l, elemlist)
+ {
+ char *tok = (char *) lfirst(l);
+
/* Ugh. Somebody ought to write a table driven version -- mjl */
- if (!strcasecmp(tok, "ISO"))
+ if (strcasecmp(tok, "ISO") == 0)
{
- DateStyle = USE_ISO_DATES;
+ newDateStyle = USE_ISO_DATES;
dcnt++;
}
- else if (!strcasecmp(tok, "SQL"))
+ else if (strcasecmp(tok, "SQL") == 0)
{
- DateStyle = USE_SQL_DATES;
+ newDateStyle = USE_SQL_DATES;
dcnt++;
}
- else if (!strncasecmp(tok, "POSTGRESQL", 8))
+ else if (strncasecmp(tok, "POSTGRESQL", 8) == 0)
{
- DateStyle = USE_POSTGRES_DATES;
+ newDateStyle = USE_POSTGRES_DATES;
dcnt++;
}
- else if (!strcasecmp(tok, "GERMAN"))
+ else if (strcasecmp(tok, "GERMAN") == 0)
{
- DateStyle = USE_GERMAN_DATES;
+ newDateStyle = USE_GERMAN_DATES;
dcnt++;
- if ((ecnt > 0) && (!EuroDates))
- ecnt++;
- EuroDates = TRUE;
+ if ((ecnt > 0) && (!newEuroDates))
+ ok = false;
+ newEuroDates = TRUE;
}
- else if (!strncasecmp(tok, "EURO", 4))
+ else if (strncasecmp(tok, "EURO", 4) == 0)
{
- EuroDates = TRUE;
- if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES))
- ecnt++;
+ newEuroDates = TRUE;
+ ecnt++;
}
- else if ((!strcasecmp(tok, "US"))
- || (!strncasecmp(tok, "NONEURO", 7)))
+ else if (strcasecmp(tok, "US") == 0
+ || strncasecmp(tok, "NONEURO", 7) == 0)
{
- EuroDates = FALSE;
- if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES))
- ecnt++;
+ newEuroDates = FALSE;
+ ecnt++;
+ if ((dcnt > 0) && (newDateStyle == USE_GERMAN_DATES))
+ ok = false;
}
- else if (!strcasecmp(tok, "DEFAULT"))
+ else if (strcasecmp(tok, "DEFAULT") == 0)
{
- DateStyle = DefaultDateStyle;
- EuroDates = DefaultEuroDates;
+ /*
+ * Easiest way to get the current DEFAULT state is to fetch
+ * the DEFAULT string from guc.c and recursively parse it.
+ *
+ * We can't simply "return assign_datestyle(...)" because we
+ * need to handle constructs like "DEFAULT, ISO".
+ */
+ int saveDateStyle = DateStyle;
+ bool saveEuroDates = EuroDates;
+ const char *subval;
+
+ subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
+ true, interactive);
+ newDateStyle = DateStyle;
+ newEuroDates = EuroDates;
+ DateStyle = saveDateStyle;
+ EuroDates = saveEuroDates;
+ if (!subval)
+ {
+ ok = false;
+ break;
+ }
+ /* Here we know that our own return value is always malloc'd */
+ /* when doit is true */
+ free((char *) subval);
+ dcnt++;
ecnt++;
}
else
- elog(ERROR, "SET DATESTYLE bad value (%s)", tok);
+ {
+ if (interactive)
+ elog(ERROR, "SET DATESTYLE: unrecognized keyword %s", tok);
+ ok = false;
+ break;
+ }
}
if (dcnt > 1 || ecnt > 1)
- elog(WARNING, "SET DATESTYLE specified conflicting settings");
+ ok = false;
- return TRUE;
-}
+ pfree(rawstring);
+ freeList(elemlist);
-static bool
-parse_datestyle(List *args)
-{
- int rstat = FALSE;
- List *arg;
- char *value;
-
- if (args == NULL)
- return reset_datestyle();
-
- Assert(IsA(args, List));
-
- foreach(arg, args)
+ if (!ok)
{
- Node *n;
-
- Assert(IsA(arg, List));
- n = lfirst(arg);
-
- /* Require untyped, stringy constants for arguments. */
- if (IsA(n, A_Const))
- {
- A_Const *p = (A_Const *) n;
- TypeName *type = p->typename;
- Value *v = &(p->val);
-
- if (type != NULL)
- {
- Value *s;
- Assert(IsA(type->names, List));
- s = (Value *) lfirst(type->names);
- elog(ERROR, "SET DATESTYLE does not allow input of type %s"
- "\n\tUse an untyped string instead", s->val.str);
- }
-
- value = v->val.str;
- }
- else
- {
- elog(ERROR, "SET DATESTYLE argument is not valid");
- value = NULL;
- }
-
- rstat = parse_datestyle_internal(value);
-
- if (rstat != TRUE)
- return rstat;
+ if (interactive)
+ elog(ERROR, "SET DATESTYLE: conflicting specifications");
+ return NULL;
}
- return rstat;
+ /*
+ * If we aren't going to do the assignment, just return OK indicator.
+ */
+ if (!doit)
+ return value;
+
+ /*
+ * Prepare the canonical string to return. GUC wants it malloc'd.
+ */
+ result = (char *) malloc(32);
+ if (!result)
+ return NULL;
+
+ switch (newDateStyle)
+ {
+ case USE_ISO_DATES:
+ strcpy(result, "ISO");
+ break;
+ case USE_SQL_DATES:
+ strcpy(result, "SQL");
+ break;
+ case USE_GERMAN_DATES:
+ strcpy(result, "GERMAN");
+ break;
+ default:
+ strcpy(result, "POSTGRESQL");
+ break;
+ }
+ strcat(result, newEuroDates ? ", EURO" : ", US");
+
+ /*
+ * Finally, it's safe to assign to the global variables;
+ * the assignment cannot fail now.
+ */
+ DateStyle = newDateStyle;
+ EuroDates = newEuroDates;
+
+ return result;
}
-static bool
+/*
+ * show_datestyle: GUC show_hook for datestyle
+ */
+const char *
show_datestyle(void)
{
- char buf[64];
+ static char buf[64];
- strcpy(buf, "DateStyle is ");
switch (DateStyle)
{
case USE_ISO_DATES:
- strcat(buf, "ISO");
+ strcpy(buf, "ISO");
break;
case USE_SQL_DATES:
- strcat(buf, "SQL");
+ strcpy(buf, "SQL");
break;
case USE_GERMAN_DATES:
- strcat(buf, "German");
+ strcpy(buf, "German");
break;
default:
- strcat(buf, "Postgres");
+ strcpy(buf, "Postgres");
break;
};
strcat(buf, " with ");
strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
strcat(buf, " conventions");
- elog(INFO, buf, NULL);
-
- return TRUE;
-}
-
-static bool
-reset_datestyle(void)
-{
- DateStyle = DefaultDateStyle;
- EuroDates = DefaultEuroDates;
-
- return TRUE;
-}
-
-void
-set_default_datestyle(void)
-{
- char *DBDate;
-
- /*
- * Initialize from compile-time defaults in init/globals.c. NB: this
- * is a necessary step; consider PGDATESTYLE="DEFAULT".
- */
- DefaultDateStyle = DateStyle;
- DefaultEuroDates = EuroDates;
-
- /* If the environment var is set, override compiled-in values */
- DBDate = getenv("PGDATESTYLE");
- if (DBDate == NULL)
- return;
-
- /*
- * Make a modifiable copy --- overwriting the env var doesn't seem
- * like a good idea, even though we currently won't look at it again.
- * Note that we cannot use palloc at this early stage of
- * initialization.
- */
- DBDate = strdup(DBDate);
-
- /*
- * Parse desired setting into DateStyle/EuroDates Use
- * parse_datestyle_internal() to avoid any palloc() issues per above -
- * thomas 2001-10-15
- */
- parse_datestyle_internal(DBDate);
-
- free(DBDate);
-
- /* And make it the default for future RESETs */
- DefaultDateStyle = DateStyle;
- DefaultEuroDates = EuroDates;
+ return buf;
}
-/* Timezone support
- * Working storage for strings is allocated with an arbitrary size of 64 bytes.
+/*
+ * TIMEZONE
*/
-static char *defaultTZ = NULL;
-static char TZvalue[64];
+/*
+ * Storage for TZ env var is allocated with an arbitrary size of 64 bytes.
+ */
static char tzbuf[64];
/*
- *
- * TIMEZONE
- *
+ * assign_timezone: GUC assign_hook for timezone
*/
-/* parse_timezone()
- * Handle SET TIME ZONE...
- * Try to save existing TZ environment variable for later use in RESET TIME ZONE.
- * Accept an explicit interval per SQL9x, though this is less useful than a full time zone.
- * - thomas 2001-10-11
- */
-static bool
-parse_timezone(List *args)
+const char *
+assign_timezone(const char *value, bool doit, bool interactive)
{
- List *arg;
- TypeName *type;
+ char *result;
+ char *endptr;
+ double hours;
- if (args == NULL)
- return reset_timezone();
-
- Assert(IsA(args, List));
-
- foreach(arg, args)
+ /*
+ * Check for INTERVAL 'foo'
+ */
+ if (strncasecmp(value, "interval", 8) == 0)
{
- A_Const *p;
+ const char *valueptr = value;
+ char *val;
+ Interval *interval;
- Assert(IsA(arg, List));
- p = lfirst(arg);
- Assert(IsA(p, A_Const));
-
- type = p->typename;
- if (type != NULL)
+ valueptr += 8;
+ while (isspace((unsigned char) *valueptr))
+ valueptr++;
+ if (*valueptr++ != '\'')
+ return NULL;
+ val = pstrdup(valueptr);
+ /* Check and remove trailing quote */
+ endptr = strchr(val, '\'');
+ if (!endptr || endptr[1] != '\0')
{
- Oid typeOid = typenameTypeId(type);
-
- if (typeOid == INTERVALOID)
- {
- Interval *interval;
-
- interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
- CStringGetDatum(p->val.val.str),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(type->typmod)));
- if (interval->month != 0)
- elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
- CTimeZone = interval->time;
- }
- else if (typeOid == FLOAT8OID)
- {
- float8 time;
-
- time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
- CTimeZone = time * 3600;
- }
-
- /*
- * We do not actually generate an integer constant in gram.y
- * so this is not used...
- */
- else if (typeOid == INT4OID)
- {
- int32 time;
-
- time = p->val.val.ival;
- CTimeZone = time * 3600;
- }
- else
- {
- elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error");
- }
-
+ pfree(val);
+ return NULL;
+ }
+ *endptr = '\0';
+ /*
+ * Try to parse it. XXX an invalid interval format will result in
+ * elog, which is not desirable for GUC. We did what we could to
+ * guard against this in flatten_set_variable_args, but a string
+ * coming in from postgresql.conf might contain anything.
+ */
+ interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
+ CStringGetDatum(val),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1)));
+ pfree(val);
+ if (interval->month != 0)
+ {
+ if (interactive)
+ elog(ERROR, "SET TIME ZONE: illegal INTERVAL; month not allowed");
+ pfree(interval);
+ return NULL;
+ }
+ if (doit)
+ {
+ CTimeZone = interval->time;
HasCTZSet = true;
}
+ pfree(interval);
+ }
+ else
+ {
+ /*
+ * Try it as a numeric number of hours (possibly fractional).
+ */
+ hours = strtod(value, &endptr);
+ if (endptr != value && *endptr == '\0')
+ {
+ if (doit)
+ {
+ CTimeZone = hours * 3600;
+ HasCTZSet = true;
+ }
+ }
+ else if (strcasecmp(value, "UNKNOWN") == 0)
+ {
+ /*
+ * Clear any TZ value we may have established.
+ *
+ * unsetenv() works fine, but is BSD, not POSIX, and is not
+ * available under Solaris, among others. Apparently putenv()
+ * called as below clears the process-specific environment
+ * variables. Other reasonable arguments to putenv() (e.g.
+ * "TZ=", "TZ", "") result in a core dump (under Linux anyway).
+ * - thomas 1998-01-26
+ */
+ if (doit)
+ {
+ if (tzbuf[0] == 'T')
+ {
+ strcpy(tzbuf, "=");
+ if (putenv(tzbuf) != 0)
+ elog(ERROR, "Unable to clear TZ environment variable");
+ tzset();
+ }
+ HasCTZSet = false;
+ }
+ }
else
{
- char *tok;
- char *value;
-
- value = p->val.val.str;
-
- while ((value = get_token(&tok, NULL, value)) != 0)
+ /*
+ * Otherwise assume it is a timezone name.
+ *
+ * XXX unfortunately we have no reasonable way to check whether a
+ * timezone name is good, so we have to just assume that it is.
+ */
+ if (doit)
{
- /* Not yet tried to save original value from environment? */
- if (defaultTZ == NULL)
- {
- /* found something? then save it for later */
- if ((defaultTZ = getenv("TZ")) != NULL)
- strcpy(TZvalue, defaultTZ);
-
- /* found nothing so mark with an invalid pointer */
- else
- defaultTZ = (char *) -1;
- }
-
strcpy(tzbuf, "TZ=");
- strcat(tzbuf, tok);
- if (putenv(tzbuf) != 0)
- elog(ERROR, "Unable to set TZ environment variable to %s", tok);
-
+ strncat(tzbuf, value, sizeof(tzbuf)-4);
+ if (putenv(tzbuf) != 0) /* shouldn't happen? */
+ elog(LOG, "assign_timezone: putenv failed");
tzset();
+ HasCTZSet = false;
}
-
- HasCTZSet = false;
}
}
- return TRUE;
-} /* parse_timezone() */
+ /*
+ * If we aren't going to do the assignment, just return OK indicator.
+ */
+ if (!doit)
+ return value;
-static bool
+ /*
+ * Prepare the canonical string to return. GUC wants it malloc'd.
+ */
+ result = (char *) malloc(sizeof(tzbuf));
+ if (!result)
+ return NULL;
+
+ if (HasCTZSet)
+ {
+ snprintf(result, sizeof(tzbuf), "%.5f",
+ (double) CTimeZone / 3600.0);
+ }
+ else if (tzbuf[0] == 'T')
+ {
+ strcpy(result, tzbuf + 3);
+ }
+ else
+ {
+ strcpy(result, "UNKNOWN");
+ }
+
+ return result;
+}
+
+/*
+ * show_timezone: GUC show_hook for timezone
+ */
+const char *
show_timezone(void)
{
char *tzn;
@@ -516,186 +406,68 @@ show_timezone(void)
interval.month = 0;
interval.time = CTimeZone;
- tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval)));
+ tzn = DatumGetCString(DirectFunctionCall1(interval_out,
+ IntervalPGetDatum(&interval)));
}
else
tzn = getenv("TZ");
if (tzn != NULL)
- elog(INFO, "Time zone is '%s'", tzn);
- else
- elog(INFO, "Time zone is unset");
-
- return TRUE;
-} /* show_timezone() */
-
-/* reset_timezone()
- * Set TZ environment variable to original value.
- * Note that if TZ was originally not set, TZ should be cleared.
- * unsetenv() works fine, but is BSD, not POSIX, and is not available
- * under Solaris, among others. Apparently putenv() called as below
- * clears the process-specific environment variables.
- * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
- * in a core dump (under Linux anyway).
- * - thomas 1998-01-26
- */
-static bool
-reset_timezone(void)
-{
- if (HasCTZSet)
- HasCTZSet = false;
-
- /* no time zone has been set in this session? */
- else if (defaultTZ == NULL)
- {
- }
-
- /* time zone was set and original explicit time zone available? */
- else if (defaultTZ != (char *) -1)
- {
- strcpy(tzbuf, "TZ=");
- strcat(tzbuf, TZvalue);
- if (putenv(tzbuf) != 0)
- elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
- tzset();
- }
-
- /*
- * otherwise, time zone was set but no original explicit time zone
- * available
- */
- else
- {
- strcpy(tzbuf, "=");
- if (putenv(tzbuf) != 0)
- elog(ERROR, "Unable to clear TZ environment variable");
- tzset();
- }
-
- return TRUE;
-} /* reset_timezone() */
+ return tzn;
+ return "unknown";
+}
/*
- *
- * SET TRANSACTION
- *
+ * SET TRANSACTION ISOLATION LEVEL
*/
-static bool
-parse_XactIsoLevel(List *args)
+const char *
+assign_XactIsoLevel(const char *value, bool doit, bool interactive)
{
- char *value;
-
- if (args == NULL)
- return reset_XactIsoLevel();
-
- Assert(IsA(args, List));
- Assert(IsA(lfirst(args), A_Const));
- /* Should only get one argument from the parser */
- if (lnext(args) != NIL)
- elog(ERROR, "SET TRANSACTION ISOLATION LEVEL takes only one argument");
-
- Assert(((A_Const *) lfirst(args))->val.type = T_String);
- value = ((A_Const *) lfirst(args))->val.val.str;
-
- if (SerializableSnapshot != NULL)
- {
+ if (doit && interactive && SerializableSnapshot != NULL)
elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
- return TRUE;
- }
if (strcmp(value, "serializable") == 0)
- XactIsoLevel = XACT_SERIALIZABLE;
+ { if (doit) XactIsoLevel = XACT_SERIALIZABLE; }
else if (strcmp(value, "read committed") == 0)
- XactIsoLevel = XACT_READ_COMMITTED;
+ { if (doit) XactIsoLevel = XACT_READ_COMMITTED; }
+ else if (strcmp(value, "default") == 0)
+ { if (doit) XactIsoLevel = DefaultXactIsoLevel; }
else
- elog(ERROR, "invalid transaction isolation level: %s", value);
+ return NULL;
- return TRUE;
+ return value;
}
-static bool
+const char *
show_XactIsoLevel(void)
{
-
if (XactIsoLevel == XACT_SERIALIZABLE)
- elog(INFO, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
+ return "SERIALIZABLE";
else
- elog(INFO, "TRANSACTION ISOLATION LEVEL is READ COMMITTED");
- return TRUE;
-}
-
-static bool
-reset_XactIsoLevel(void)
-{
-
- if (SerializableSnapshot != NULL)
- {
- elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
- return TRUE;
- }
-
- XactIsoLevel = DefaultXactIsoLevel;
-
- return TRUE;
+ return "READ COMMITTED";
}
/*
* Random number seed
*/
-static bool
-parse_random_seed(List *args)
+
+bool
+assign_random_seed(double value, bool doit, bool interactive)
{
- A_Const *p;
- double seed = 0;
-
- if (args == NULL)
- return reset_random_seed();
-
- Assert(IsA(args, List));
- /* Should only get one argument from the parser */
- if (lnext(args) != NIL)
- elog(ERROR, "SET SEED takes only one argument");
-
- p = lfirst(args);
- Assert(IsA(p, A_Const));
-
- if ((p->val.type == T_String)
- || (p->val.type == T_Float))
- {
- seed = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
- }
- else if (p->val.type == T_Integer)
- {
- seed = p->val.val.ival;
- }
- else
- {
- elog(ERROR, "SET SEED internal coding error");
- }
-
- DirectFunctionCall1(setseed, Float8GetDatum(seed));
-
- return (TRUE);
+ /* Can't really roll back on error, so ignore non-interactive setting */
+ if (doit && interactive)
+ DirectFunctionCall1(setseed, Float8GetDatum(value));
+ return true;
}
-static bool
+const char *
show_random_seed(void)
{
- elog(INFO, "Seed for random number generator is unavailable");
- return (TRUE);
-}
-
-static bool
-reset_random_seed(void)
-{
- double seed = 0.5;
-
- DirectFunctionCall1(setseed, Float8GetDatum(seed));
- return (TRUE);
+ return "unavailable";
}
@@ -708,259 +480,108 @@ reset_random_seed(void)
* clients.
*/
-static bool
-parse_client_encoding(List *args)
+const char *
+assign_client_encoding(const char *value, bool doit, bool interactive)
{
- char *value;
-
#ifdef MULTIBYTE
int encoding;
-#endif
+ int old_encoding = 0;
- if (args == NULL)
- return reset_client_encoding();
-
- if (lnext(args) != NIL)
- elog(ERROR, "SET CLIENT ENCODING takes only one argument");
-
- Assert(IsA(lfirst(args), A_Const));
- if (((A_Const *) lfirst(args))->val.type != T_String)
- {
- elog(ERROR, "SET CLIENT_ENCODING requires an encoding name");
- }
-
- value = ((A_Const *) lfirst(args))->val.val.str;
-
-#ifdef MULTIBYTE
encoding = pg_valid_client_encoding(value);
if (encoding < 0)
+ return NULL;
+ /*
+ * Ugly API here ... can't test validity without setting new encoding...
+ */
+ if (!doit)
+ old_encoding = pg_get_client_encoding();
+ if (pg_set_client_encoding(encoding) < 0)
{
- if (value)
- elog(ERROR, "Client encoding '%s' is not supported", value);
- else
- elog(ERROR, "No client encoding is specified");
- }
- else
- {
- if (pg_set_client_encoding(encoding) < 0)
- {
+ if (interactive)
elog(ERROR, "Conversion between %s and %s is not supported",
value, GetDatabaseEncodingName());
- }
+ return NULL;
}
+ if (!doit)
+ pg_set_client_encoding(old_encoding);
#else
- if (value &&
- strcasecmp(value, pg_get_client_encoding_name()) != 0)
- elog(ERROR, "Client encoding %s is not supported", value);
+ if (strcasecmp(value, pg_get_client_encoding_name()) != 0)
+ return NULL;
#endif
- return TRUE;
+
+ return value;
}
-static bool
-show_client_encoding(void)
+
+const char *
+assign_server_encoding(const char *value, bool doit, bool interactive)
{
- elog(INFO, "Current client encoding is '%s'",
- pg_get_client_encoding_name());
- return TRUE;
+ if (interactive)
+ elog(ERROR, "SET SERVER_ENCODING is not supported");
+ /* Pretend never to fail in noninteractive case */
+ return value;
}
-static bool
-reset_client_encoding(void)
-{
-#ifdef MULTIBYTE
- int encoding;
- char *env = getenv("PGCLIENTENCODING");
-
- if (env)
- {
- encoding = pg_char_to_encoding(env);
- if (encoding < 0)
- encoding = GetDatabaseEncoding();
- }
- else
- encoding = GetDatabaseEncoding();
-
- pg_set_client_encoding(encoding);
-#endif
- return TRUE;
-}
-
-/* Called during MULTIBYTE backend startup ... */
-void
-set_default_client_encoding(void)
-{
- reset_client_encoding();
-}
-
-
-static bool
-parse_server_encoding(List *args)
-{
- elog(INFO, "SET SERVER_ENCODING is not supported");
- return TRUE;
-}
-
-static bool
+const char *
show_server_encoding(void)
{
- elog(INFO, "Current server encoding is '%s'", GetDatabaseEncodingName());
- return TRUE;
+ return GetDatabaseEncodingName();
}
-static bool
-reset_server_encoding(void)
+
+/*
+ * SET SESSION AUTHORIZATION
+ *
+ * Note: when resetting session auth after an error, we can't expect to do
+ * catalog lookups. Hence, the stored form of the value is always a numeric
+ * userid that can be re-used directly.
+ */
+const char *
+assign_session_authorization(const char *value, bool doit, bool interactive)
{
- elog(INFO, "RESET SERVER_ENCODING is not supported");
- return TRUE;
+ Oid usesysid;
+ char *endptr;
+ char *result;
+
+ usesysid = (Oid) strtoul(value, &endptr, 10);
+
+ if (endptr != value && *endptr == '\0' && OidIsValid(usesysid))
+ {
+ /* use the numeric user ID */
+ }
+ else
+ {
+ HeapTuple userTup;
+
+ userTup = SearchSysCache(SHADOWNAME,
+ PointerGetDatum(value),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(userTup))
+ {
+ if (interactive)
+ elog(ERROR, "user \"%s\" does not exist", value);
+ return NULL;
+ }
+
+ usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+ ReleaseSysCache(userTup);
+ }
+
+ if (doit)
+ SetSessionAuthorization(usesysid);
+
+ result = (char *) malloc(32);
+ if (!result)
+ return NULL;
+
+ snprintf(result, 32, "%lu", (unsigned long) usesysid);
+
+ return result;
}
-
-static bool
+const char *
show_session_authorization(void)
{
- elog(INFO, "Current session authorization is '%s'",
- GetUserName(GetSessionUserId()));
- return TRUE;
-}
-
-
-
-/* SetPGVariable()
- * Dispatcher for handling SET commands.
- * Special cases ought to be removed and handled separately by TCOP
- */
-void
-SetPGVariable(const char *name, List *args)
-{
- if (strcasecmp(name, "datestyle") == 0)
- parse_datestyle(args);
- else if (strcasecmp(name, "timezone") == 0)
- parse_timezone(args);
- else if (strcasecmp(name, "XactIsoLevel") == 0)
- parse_XactIsoLevel(args);
- else if (strcasecmp(name, "client_encoding") == 0)
- parse_client_encoding(args);
- else if (strcasecmp(name, "server_encoding") == 0)
- parse_server_encoding(args);
- else if (strcasecmp(name, "seed") == 0)
- parse_random_seed(args);
- else
- {
- /*
- * For routines defined somewhere else, go ahead and extract the
- * string argument to match the original interface definition.
- * Later, we can change this code too...
- */
- char *value;
-
- if (args != NULL)
- {
- A_Const *n;
-
- /* Ensure one argument only... */
- if (lnext(args) != NIL)
- elog(ERROR, "SET %s takes only one argument", name);
-
- n = (A_Const *) lfirst(args);
- if ((n->val.type == T_String)
- || (n->val.type == T_Float))
- {
- value = n->val.val.str;
- }
- else if (n->val.type == T_Integer)
- {
- /* We should convert back to a string. */
- value = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(n->val.val.ival)));
- }
- else
- {
- elog(ERROR, "SET %s accepts a string argument for this parameter"
- "\n\tInternal coding error: report to thomas@fourpalms.org",
- name);
- value = NULL;
- }
- }
- else
- {
- value = NULL;
- }
-
- if (strcasecmp(name, "session_authorization") == 0)
- SetSessionAuthorization(value);
- else
- SetConfigOption(name,
- value,
- (superuser() ? PGC_SUSET : PGC_USERSET),
- PGC_S_SESSION);
- }
- return;
-}
-
-void
-GetPGVariable(const char *name)
-{
- if (strcasecmp(name, "datestyle") == 0)
- show_datestyle();
- else if (strcasecmp(name, "timezone") == 0)
- show_timezone();
- else if (strcasecmp(name, "XactIsoLevel") == 0)
- show_XactIsoLevel();
- else if (strcasecmp(name, "client_encoding") == 0)
- show_client_encoding();
- else if (strcasecmp(name, "server_encoding") == 0)
- show_server_encoding();
- else if (strcasecmp(name, "seed") == 0)
- show_random_seed();
- else if (strcasecmp(name, "session_authorization") == 0)
- show_session_authorization();
- else if (strcasecmp(name, "all") == 0)
- {
- ShowAllGUCConfig();
- show_datestyle();
- show_timezone();
- show_XactIsoLevel();
- show_client_encoding();
- show_server_encoding();
- show_random_seed();
- }
- else
- {
- const char *val = GetConfigOption(name);
-
- elog(INFO, "%s is %s", name, val);
- }
-}
-
-void
-ResetPGVariable(const char *name)
-{
- if (strcasecmp(name, "datestyle") == 0)
- reset_datestyle();
- else if (strcasecmp(name, "timezone") == 0)
- reset_timezone();
- else if (strcasecmp(name, "XactIsoLevel") == 0)
- reset_XactIsoLevel();
- else if (strcasecmp(name, "client_encoding") == 0)
- reset_client_encoding();
- else if (strcasecmp(name, "server_encoding") == 0)
- reset_server_encoding();
- else if (strcasecmp(name, "seed") == 0)
- reset_random_seed();
- else if (strcasecmp(name, "session_authorization") == 0)
- SetSessionAuthorization(NULL);
- else if (strcasecmp(name, "all") == 0)
- {
- reset_random_seed();
- /* reset_server_encoding(); */
- reset_client_encoding();
- reset_datestyle();
- reset_timezone();
- /* should we reset session authorization here? */
-
- ResetAllOptions(false);
- }
- else
- SetConfigOption(name, NULL,
- superuser() ? PGC_SUSET : PGC_USERSET,
- PGC_S_SESSION);
+ return GetUserName(GetSessionUserId());
}
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index 9c79e7b78d..227fcc35e5 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.50 2002/04/03 05:39:29 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.51 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -125,7 +125,7 @@ main(int argc, char *argv[])
* and COLLATE will be overridden later from pg_control if we are
* in an already-initialized database. We set them here so that
* they will be available to fill pg_control during initdb. The
- * other ones will get reset later in ResetAllOptions, but we set
+ * other ones will get reset later in InitializeGUCOptions, but we set
* them here to get already localized behavior during startup
* (e.g., error messages).
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a3751d3698..909847dc85 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.185 2002/05/13 20:39:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.186 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2342,6 +2342,7 @@ _copyVariableSetStmt(VariableSetStmt *from)
if (from->name)
newnode->name = pstrdup(from->name);
Node_Copy(from, newnode, args);
+ newnode->is_local = from->is_local;
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index cf203243f1..1f0d175326 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.132 2002/05/12 23:43:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.133 2002/05/17 01:19:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1173,6 +1173,8 @@ _equalVariableSetStmt(VariableSetStmt *a, VariableSetStmt *b)
return false;
if (!equal(a->args, b->args))
return false;
+ if (a->is_local != b->is_local)
+ return false;
return true;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bd3a7a0832..0009b9df2f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.315 2002/05/13 17:45:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.316 2002/05/17 01:19:17 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -128,6 +128,7 @@ static void doNegateFloat(Value *v);
PrivTarget *privtarget;
InsertStmt *istmt;
+ VariableSetStmt *vsetstmt;
}
%type stmt, schema_stmt,
@@ -246,6 +247,8 @@ static void doNegateFloat(Value *v);
%type insert_rest
+%type set_rest
+
%type OptTableElement, ConstraintElem
%type columnDef
%type def_elem
@@ -563,12 +566,12 @@ AlterUserStmt: ALTER USER UserId OptUserList
;
-AlterUserSetStmt: ALTER USER UserId VariableSetStmt
+AlterUserSetStmt: ALTER USER UserId SET set_rest
{
AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
n->user = $3;
- n->variable = ((VariableSetStmt *)$4)->name;
- n->value = ((VariableSetStmt *)$4)->args;
+ n->variable = $5->name;
+ n->value = $5->args;
$$ = (Node *)n;
}
| ALTER USER UserId VariableResetStmt
@@ -576,7 +579,7 @@ AlterUserSetStmt: ALTER USER UserId VariableSetStmt
AlterUserSetStmt *n = makeNode(AlterUserSetStmt);
n->user = $3;
n->variable = ((VariableResetStmt *)$4)->name;
- n->value = NULL;
+ n->value = NIL;
$$ = (Node *)n;
}
;
@@ -834,63 +837,83 @@ schema_stmt: CreateStmt
*
*****************************************************************************/
-VariableSetStmt: SET ColId TO var_list_or_default
+VariableSetStmt: SET set_rest
{
- VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = $2;
- n->args = $4;
+ VariableSetStmt *n = $2;
+ n->is_local = false;
$$ = (Node *) n;
}
- | SET ColId '=' var_list_or_default
+ | SET LOCAL set_rest
{
- VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = $2;
- n->args = $4;
+ VariableSetStmt *n = $3;
+ n->is_local = true;
$$ = (Node *) n;
}
- | SET TIME ZONE zone_value
+ | SET SESSION set_rest
{
- VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = "timezone";
- if ($4 != NULL)
- n->args = makeList1($4);
+ VariableSetStmt *n = $3;
+ n->is_local = false;
$$ = (Node *) n;
}
- | SET TRANSACTION ISOLATION LEVEL opt_level
+ ;
+
+set_rest: ColId TO var_list_or_default
{
VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = "XactIsoLevel";
- n->args = makeList1(makeStringConst($5, NULL));
- $$ = (Node *) n;
+ n->name = $1;
+ n->args = $3;
+ $$ = n;
}
- | SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level
+ | ColId '=' var_list_or_default
{
VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = "default_transaction_isolation";
- n->args = makeList1(makeStringConst($8, NULL));
- $$ = (Node *) n;
+ n->name = $1;
+ n->args = $3;
+ $$ = n;
}
- | SET NAMES opt_encoding
+ | TIME ZONE zone_value
{
VariableSetStmt *n = makeNode(VariableSetStmt);
- n->name = "client_encoding";
+ n->name = "timezone";
if ($3 != NULL)
- n->args = makeList1(makeStringConst($3, NULL));
- $$ = (Node *) n;
+ n->args = makeList1($3);
+ $$ = n;
}
- | SET SESSION AUTHORIZATION ColId_or_Sconst
+ | TRANSACTION ISOLATION LEVEL opt_level
+ {
+ VariableSetStmt *n = makeNode(VariableSetStmt);
+ n->name = "TRANSACTION ISOLATION LEVEL";
+ n->args = makeList1(makeStringConst($4, NULL));
+ $$ = n;
+ }
+ | SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level
+ {
+ VariableSetStmt *n = makeNode(VariableSetStmt);
+ n->name = "default_transaction_isolation";
+ n->args = makeList1(makeStringConst($7, NULL));
+ $$ = n;
+ }
+ | NAMES opt_encoding
+ {
+ VariableSetStmt *n = makeNode(VariableSetStmt);
+ n->name = "client_encoding";
+ if ($2 != NULL)
+ n->args = makeList1(makeStringConst($2, NULL));
+ $$ = n;
+ }
+ | SESSION AUTHORIZATION ColId_or_Sconst
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "session_authorization";
- n->args = makeList1(makeStringConst($4, NULL));
- $$ = (Node *) n;
+ n->args = makeList1(makeStringConst($3, NULL));
+ $$ = n;
}
- | SET SESSION AUTHORIZATION DEFAULT
+ | SESSION AUTHORIZATION DEFAULT
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "session_authorization";
n->args = NIL;
- $$ = (Node *) n;
+ $$ = n;
}
;
@@ -926,10 +949,10 @@ opt_boolean: TRUE_P { $$ = "true"; }
/* Timezone values can be:
* - a string such as 'pst8pdt'
- * - a column identifier such as "pst8pdt"
+ * - an identifier such as "pst8pdt"
* - an integer or floating point number
* - a time interval per SQL99
- * ConstInterval and ColId give shift/reduce errors,
+ * ColId gives reduce/reduce errors against ConstInterval and LOCAL,
* so use IDENT and reject anything which is a reserved word.
*/
zone_value: Sconst
@@ -988,25 +1011,31 @@ ColId_or_Sconst: ColId { $$ = $1; }
VariableShowStmt: SHOW ColId
{
VariableShowStmt *n = makeNode(VariableShowStmt);
- n->name = $2;
+ n->name = $2;
$$ = (Node *) n;
}
| SHOW TIME ZONE
{
VariableShowStmt *n = makeNode(VariableShowStmt);
- n->name = "timezone";
- $$ = (Node *) n;
- }
- | SHOW ALL
- {
- VariableShowStmt *n = makeNode(VariableShowStmt);
- n->name = "all";
+ n->name = "timezone";
$$ = (Node *) n;
}
| SHOW TRANSACTION ISOLATION LEVEL
{
VariableShowStmt *n = makeNode(VariableShowStmt);
- n->name = "XactIsoLevel";
+ n->name = "TRANSACTION ISOLATION LEVEL";
+ $$ = (Node *) n;
+ }
+ | SHOW SESSION AUTHORIZATION
+ {
+ VariableShowStmt *n = makeNode(VariableShowStmt);
+ n->name = "session_authorization";
+ $$ = (Node *) n;
+ }
+ | SHOW ALL
+ {
+ VariableShowStmt *n = makeNode(VariableShowStmt);
+ n->name = "all";
$$ = (Node *) n;
}
;
@@ -1014,19 +1043,19 @@ VariableShowStmt: SHOW ColId
VariableResetStmt: RESET ColId
{
VariableResetStmt *n = makeNode(VariableResetStmt);
- n->name = $2;
+ n->name = $2;
$$ = (Node *) n;
}
| RESET TIME ZONE
{
VariableResetStmt *n = makeNode(VariableResetStmt);
- n->name = "timezone";
+ n->name = "timezone";
$$ = (Node *) n;
}
| RESET TRANSACTION ISOLATION LEVEL
{
VariableResetStmt *n = makeNode(VariableResetStmt);
- n->name = "XactIsoLevel";
+ n->name = "TRANSACTION ISOLATION LEVEL";
$$ = (Node *) n;
}
| RESET SESSION AUTHORIZATION
@@ -1038,7 +1067,7 @@ VariableResetStmt: RESET ColId
| RESET ALL
{
VariableResetStmt *n = makeNode(VariableResetStmt);
- n->name = "all";
+ n->name = "all";
$$ = (Node *) n;
}
;
@@ -3329,12 +3358,12 @@ opt_equal: '=' { $$ = TRUE; }
*
*****************************************************************************/
-AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
+AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest
{
AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
n->dbname = $3;
- n->variable = ((VariableSetStmt *)$4)->name;
- n->value = ((VariableSetStmt *)$4)->args;
+ n->variable = $5->name;
+ n->value = $5->args;
$$ = (Node *)n;
}
| ALTER DATABASE database_name VariableResetStmt
@@ -3342,7 +3371,7 @@ AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt);
n->dbname = $3;
n->variable = ((VariableResetStmt *)$4)->name;
- n->value = NULL;
+ n->value = NIL;
$$ = (Node *)n;
}
;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index a3a8f2521e..1513f13878 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.273 2002/05/05 00:03:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.274 2002/05/17 01:19:17 tgl Exp $
*
* NOTES
*
@@ -404,12 +404,7 @@ PostmasterMain(int argc, char *argv[])
/*
* Options setup
*/
- ResetAllOptions(true);
-
- /* PGPORT environment variable, if set, overrides GUC setting */
- if (getenv("PGPORT"))
- SetConfigOption("port", getenv("PGPORT"),
- PGC_POSTMASTER, PGC_S_ARGV/*sortof*/);
+ InitializeGUCOptions();
potential_DataDir = getenv("PGDATA"); /* default value */
@@ -443,8 +438,8 @@ PostmasterMain(int argc, char *argv[])
/* Turn on debugging for the postmaster. */
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
sprintf(debugstr, "debug%s", optarg);
- /* We use PGC_S_SESSION because we will reset in backend */
- SetConfigOption("server_min_messages", debugstr, PGC_POSTMASTER, PGC_S_SESSION);
+ SetConfigOption("server_min_messages", debugstr,
+ PGC_POSTMASTER, PGC_S_ARGV);
pfree(debugstr);
break;
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index eaf626ace9..53bf45dce9 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.264 2002/05/10 20:22:13 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.265 2002/05/17 01:19:18 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -37,7 +37,6 @@
#include "access/xlog.h"
#include "commands/async.h"
#include "commands/trigger.h"
-#include "commands/variable.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -1184,13 +1183,10 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
- ResetAllOptions(true);
+ InitializeGUCOptions();
potential_DataDir = getenv("PGDATA");
}
- /* Check for PGDATESTYLE environment variable */
- set_default_datestyle();
-
/* ----------------
* parse command line arguments
*
@@ -1273,9 +1269,10 @@ PostgresMain(int argc, char *argv[], const char *username)
else
/*
* -d 0 allows user to prevent postmaster debug from
- * propogating to backend.
+ * propagating to backend.
*/
- SetConfigOption("server_min_messages", "notice", PGC_POSTMASTER, PGC_S_ARGV);
+ SetConfigOption("server_min_messages", "notice",
+ ctx, gucsource);
}
break;
@@ -1292,7 +1289,7 @@ PostgresMain(int argc, char *argv[], const char *username)
/*
* Use european date formats.
*/
- EuroDates = true;
+ SetConfigOption("datestyle", "euro", ctx, gucsource);
break;
case 'F':
@@ -1691,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.264 $ $Date: 2002/05/10 20:22:13 $\n");
+ puts("$Revision: 1.265 $ $Date: 2002/05/17 01:19:18 $\n");
}
/*
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9a9c062559..e72d8dfccf 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.153 2002/04/30 01:26:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.154 2002/05/17 01:19:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,7 +36,6 @@
#include "commands/trigger.h"
#include "commands/user.h"
#include "commands/vacuum.h"
-#include "commands/variable.h"
#include "commands/view.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@@ -48,6 +47,7 @@
#include "rewrite/rewriteRemove.h"
#include "tcop/utility.h"
#include "utils/acl.h"
+#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "access/xlog.h"
@@ -718,7 +718,7 @@ ProcessUtility(Node *parsetree,
{
VariableSetStmt *n = (VariableSetStmt *) parsetree;
- SetPGVariable(n->name, n->args);
+ SetPGVariable(n->name, n->args, n->is_local);
}
break;
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 1a908d9d6b..d6e0358e81 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.89 2002/04/21 19:48:12 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.90 2002/05/17 01:19:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3571,11 +3571,17 @@ EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
} /* EncodeInterval() */
-void
-ClearDateCache(bool dummy)
+/* GUC assign_hook for australian_timezones */
+bool
+ClearDateCache(bool newval, bool doit, bool interactive)
{
int i;
- for (i = 0; i < MAXDATEFIELDS; i++)
- datecache[i] = NULL;
+ if (doit)
+ {
+ for (i = 0; i < MAXDATEFIELDS; i++)
+ datecache[i] = NULL;
+ }
+
+ return true;
}
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index c5c8d312d3..ba962ac8b1 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -2,7 +2,7 @@
*
* PostgreSQL locale utilities
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.16 2002/04/03 05:39:31 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.17 2002/05/17 01:19:18 tgl Exp $
*
* Portions Copyright (c) 2002, PostgreSQL Global Development Group
*
@@ -10,89 +10,73 @@
*/
#include "postgres.h"
-#include "utils/pg_locale.h"
+
#include
+#include "utils/pg_locale.h"
+
/* GUC storage area */
-char * locale_messages;
-char * locale_monetary;
-char * locale_numeric;
-char * locale_time;
+char *locale_messages;
+char *locale_monetary;
+char *locale_numeric;
+char *locale_time;
-/* GUC parse hooks */
-
-bool locale_messages_check(const char *proposed)
-{
-#ifdef LC_MESSAGES
- return chklocale(LC_MESSAGES, proposed);
-#else
- /* We return true here so LC_MESSAGES can be set in the
- configuration file on every system. */
- return true;
-#endif
-}
-
-bool locale_monetary_check(const char *proposed)
-{
- return chklocale(LC_MONETARY, proposed);
-}
-
-bool locale_numeric_check(const char *proposed)
-{
- return chklocale(LC_NUMERIC, proposed);
-}
-
-bool locale_time_check(const char *proposed)
-{
- return chklocale(LC_TIME, proposed);
-}
/* GUC assign hooks */
-void locale_messages_assign(const char *value)
+static const char *
+locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
{
+ if (doit)
+ {
+ if (!setlocale(category, value))
+ return NULL;
+ }
+ else
+ {
+ char *save;
+
+ save = setlocale(category, NULL);
+ if (!save)
+ return NULL;
+
+ if (!setlocale(category, value))
+ return NULL;
+
+ setlocale(category, save);
+ }
+ return value;
+}
+
+const char *
+locale_messages_assign(const char *value, bool doit, bool interactive)
+{
+ /* LC_MESSAGES category does not exist everywhere, but accept it anyway */
#ifdef LC_MESSAGES
- setlocale(LC_MESSAGES, value);
+ return locale_xxx_assign(LC_MESSAGES, value, doit, interactive);
+#else
+ return value;
#endif
}
-void locale_monetary_assign(const char *value)
+const char *
+locale_monetary_assign(const char *value, bool doit, bool interactive)
{
- setlocale(LC_MONETARY, value);
+ return locale_xxx_assign(LC_MONETARY, value, doit, interactive);
}
-void locale_numeric_assign(const char *value)
+const char *
+locale_numeric_assign(const char *value, bool doit, bool interactive)
{
- setlocale(LC_NUMERIC, value);
+ return locale_xxx_assign(LC_NUMERIC, value, doit, interactive);
}
-void locale_time_assign(const char *value)
+const char *
+locale_time_assign(const char *value, bool doit, bool interactive)
{
- setlocale(LC_TIME, value);
-}
-
-
-/*
- * Returns true if the proposed string represents a valid locale of
- * the given category. This is probably pretty slow, but it's not
- * called in critical places.
- */
-bool
-chklocale(int category, const char *proposed)
-{
- char *save;
-
- save = setlocale(category, NULL);
- if (!save)
- return false;
-
- if (!setlocale(category, proposed))
- return false;
-
- setlocale(category, save);
- return true;
+ return locale_xxx_assign(LC_TIME, value, doit, interactive);
}
@@ -123,7 +107,6 @@ lc_collate_is_c(void)
}
-
/*
* Return the POSIX lconv struct (contains number/money formatting
* information) with locale information for all categories.
@@ -131,10 +114,11 @@ lc_collate_is_c(void)
struct lconv *
PGLC_localeconv(void)
{
- struct lconv *extlconv;
static bool CurrentLocaleConvValid = false;
static struct lconv CurrentLocaleConv;
+ struct lconv *extlconv;
+
/* Did we do it already? */
if (CurrentLocaleConvValid)
return &CurrentLocaleConv;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 78cb6306e0..88528b9a06 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.104 2002/05/12 23:43:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.105 2002/05/17 01:19:18 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -2576,27 +2576,33 @@ quote_identifier(const char *ident)
* and contains only lowercase letters, digits, and underscores, *and* is
* not any SQL keyword. Otherwise, supply quotes.
*/
+ int nquotes = 0;
bool safe;
+ const char *ptr;
char *result;
+ char *optr;
/*
* would like to use macros here, but they might yield
* unwanted locale-specific results...
*/
safe = ((ident[0] >= 'a' && ident[0] <= 'z') || ident[0] == '_');
- if (safe)
+
+ for (ptr = ident; *ptr; ptr++)
{
- const char *ptr;
+ char ch = *ptr;
- for (ptr = ident + 1; *ptr; ptr++)
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= '0' && ch <= '9') ||
+ (ch == '_'))
{
- char ch = *ptr;
-
- safe = ((ch >= 'a' && ch <= 'z') ||
- (ch >= '0' && ch <= '9') ||
- (ch == '_'));
- if (!safe)
- break;
+ /* okay */
+ }
+ else
+ {
+ safe = false;
+ if (ch == '"')
+ nquotes++;
}
}
@@ -2618,8 +2624,21 @@ quote_identifier(const char *ident)
if (safe)
return ident; /* no change needed */
- result = (char *) palloc(strlen(ident) + 2 + 1);
- sprintf(result, "\"%s\"", ident);
+ result = (char *) palloc(strlen(ident) + nquotes + 2 + 1);
+
+ optr = result;
+ *optr++ = '"';
+ for (ptr = ident; *ptr; ptr++)
+ {
+ char ch = *ptr;
+
+ if (ch == '"')
+ *optr++ = '"';
+ *optr++ = ch;
+ }
+ *optr++ = '"';
+ *optr = '\0';
+
return result;
}
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 572e21ba83..a1813b67b8 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.97 2002/05/05 00:03:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.98 2002/05/17 01:19:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -841,105 +841,68 @@ elog_message_prefix(int lev)
/*
* GUC support routines
*/
-
-bool
-check_server_min_messages(const char *lev)
+const char *
+assign_server_min_messages(const char *newval,
+ bool doit, bool interactive)
{
- if (strcasecmp(lev, "debug") == 0 ||
- strcasecmp(lev, "debug5") == 0 ||
- strcasecmp(lev, "debug4") == 0 ||
- strcasecmp(lev, "debug3") == 0 ||
- strcasecmp(lev, "debug2") == 0 ||
- strcasecmp(lev, "debug1") == 0 ||
- strcasecmp(lev, "info") == 0 ||
- strcasecmp(lev, "notice") == 0 ||
- strcasecmp(lev, "warning") == 0 ||
- strcasecmp(lev, "error") == 0 ||
- strcasecmp(lev, "log") == 0 ||
- strcasecmp(lev, "fatal") == 0 ||
- strcasecmp(lev, "panic") == 0)
- return true;
- return false;
-}
-
-void
-assign_server_min_messages(const char *lev)
-{
- if (strcasecmp(lev, "debug") == 0)
- server_min_messages = DEBUG5;
- else if (strcasecmp(lev, "debug5") == 0)
- server_min_messages = DEBUG5;
- else if (strcasecmp(lev, "debug4") == 0)
- server_min_messages = DEBUG4;
- else if (strcasecmp(lev, "debug3") == 0)
- server_min_messages = DEBUG3;
- else if (strcasecmp(lev, "debug2") == 0)
- server_min_messages = DEBUG2;
- else if (strcasecmp(lev, "debug1") == 0)
- server_min_messages = DEBUG1;
- else if (strcasecmp(lev, "info") == 0)
- server_min_messages = INFO;
- else if (strcasecmp(lev, "notice") == 0)
- server_min_messages = NOTICE;
- else if (strcasecmp(lev, "warning") == 0)
- server_min_messages = WARNING;
- else if (strcasecmp(lev, "error") == 0)
- server_min_messages = ERROR;
- else if (strcasecmp(lev, "log") == 0)
- server_min_messages = LOG;
- else if (strcasecmp(lev, "fatal") == 0)
- server_min_messages = FATAL;
- else if (strcasecmp(lev, "panic") == 0)
- server_min_messages = PANIC;
+ if (strcasecmp(newval, "debug") == 0)
+ { if (doit) server_min_messages = DEBUG1; }
+ else if (strcasecmp(newval, "debug5") == 0)
+ { if (doit) server_min_messages = DEBUG5; }
+ else if (strcasecmp(newval, "debug4") == 0)
+ { if (doit) server_min_messages = DEBUG4; }
+ else if (strcasecmp(newval, "debug3") == 0)
+ { if (doit) server_min_messages = DEBUG3; }
+ else if (strcasecmp(newval, "debug2") == 0)
+ { if (doit) server_min_messages = DEBUG2; }
+ else if (strcasecmp(newval, "debug1") == 0)
+ { if (doit) server_min_messages = DEBUG1; }
+ else if (strcasecmp(newval, "info") == 0)
+ { if (doit) server_min_messages = INFO; }
+ else if (strcasecmp(newval, "notice") == 0)
+ { if (doit) server_min_messages = NOTICE; }
+ else if (strcasecmp(newval, "warning") == 0)
+ { if (doit) server_min_messages = WARNING; }
+ else if (strcasecmp(newval, "error") == 0)
+ { if (doit) server_min_messages = ERROR; }
+ else if (strcasecmp(newval, "log") == 0)
+ { if (doit) server_min_messages = LOG; }
+ else if (strcasecmp(newval, "fatal") == 0)
+ { if (doit) server_min_messages = FATAL; }
+ else if (strcasecmp(newval, "panic") == 0)
+ { if (doit) server_min_messages = PANIC; }
else
- /* Can't get here unless guc.c screwed up */
- elog(ERROR, "bogus server_min_messages %s", lev);
+ return NULL; /* fail */
+ return newval; /* OK */
}
-bool
-check_client_min_messages(const char *lev)
+const char *
+assign_client_min_messages(const char *newval,
+ bool doit, bool interactive)
{
- if (strcasecmp(lev, "debug") == 0 ||
- strcasecmp(lev, "debug5") == 0 ||
- strcasecmp(lev, "debug4") == 0 ||
- strcasecmp(lev, "debug3") == 0 ||
- strcasecmp(lev, "debug2") == 0 ||
- strcasecmp(lev, "debug1") == 0 ||
- strcasecmp(lev, "log") == 0 ||
- strcasecmp(lev, "info") == 0 ||
- strcasecmp(lev, "notice") == 0 ||
- strcasecmp(lev, "warning") == 0 ||
- strcasecmp(lev, "error") == 0)
- return true;
- return false;
-}
-
-void
-assign_client_min_messages(const char *lev)
-{
- if (strcasecmp(lev, "debug") == 0)
- client_min_messages = DEBUG5;
- else if (strcasecmp(lev, "debug5") == 0)
- client_min_messages = DEBUG5;
- else if (strcasecmp(lev, "debug4") == 0)
- client_min_messages = DEBUG4;
- else if (strcasecmp(lev, "debug3") == 0)
- client_min_messages = DEBUG3;
- else if (strcasecmp(lev, "debug2") == 0)
- client_min_messages = DEBUG2;
- else if (strcasecmp(lev, "debug1") == 0)
- client_min_messages = DEBUG1;
- else if (strcasecmp(lev, "log") == 0)
- client_min_messages = LOG;
- else if (strcasecmp(lev, "info") == 0)
- client_min_messages = INFO;
- else if (strcasecmp(lev, "notice") == 0)
- client_min_messages = NOTICE;
- else if (strcasecmp(lev, "warning") == 0)
- client_min_messages = WARNING;
- else if (strcasecmp(lev, "error") == 0)
- client_min_messages = ERROR;
+ if (strcasecmp(newval, "debug") == 0)
+ { if (doit) client_min_messages = DEBUG1; }
+ else if (strcasecmp(newval, "debug5") == 0)
+ { if (doit) client_min_messages = DEBUG5; }
+ else if (strcasecmp(newval, "debug4") == 0)
+ { if (doit) client_min_messages = DEBUG4; }
+ else if (strcasecmp(newval, "debug3") == 0)
+ { if (doit) client_min_messages = DEBUG3; }
+ else if (strcasecmp(newval, "debug2") == 0)
+ { if (doit) client_min_messages = DEBUG2; }
+ else if (strcasecmp(newval, "debug1") == 0)
+ { if (doit) client_min_messages = DEBUG1; }
+ else if (strcasecmp(newval, "log") == 0)
+ { if (doit) client_min_messages = LOG; }
+ else if (strcasecmp(newval, "info") == 0)
+ { if (doit) client_min_messages = INFO; }
+ else if (strcasecmp(newval, "notice") == 0)
+ { if (doit) client_min_messages = NOTICE; }
+ else if (strcasecmp(newval, "warning") == 0)
+ { if (doit) client_min_messages = WARNING; }
+ else if (strcasecmp(newval, "error") == 0)
+ { if (doit) client_min_messages = ERROR; }
else
- /* Can't get here unless guc.c screwed up */
- elog(ERROR, "bogus client_min_messages %s", lev);
+ return NULL; /* fail */
+ return newval; /* OK */
}
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 4cc9d396c7..fd3f191d5c 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.90 2002/05/06 19:47:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.91 2002/05/17 01:19:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -614,6 +614,9 @@ InitializeSessionUserId(const char *username)
SetSessionUserId(usesysid); /* sets CurrentUserId too */
+ /* Record username as a config option too */
+ SetConfigOption("session_authorization", username,
+ PGC_BACKEND, PGC_S_OVERRIDE);
/*
* Set up user-specific configuration variables. This is a good
@@ -653,23 +656,16 @@ InitializeSessionUserIdStandalone(void)
* Change session auth ID while running
*
* Only a superuser may set auth ID to something other than himself.
- *
- * username == NULL implies reset to default (AuthenticatedUserId).
*/
void
-SetSessionAuthorization(const char *username)
+SetSessionAuthorization(Oid userid)
{
- Oid userid;
+ /* Must have authenticated already, else can't make permission check */
+ AssertState(OidIsValid(AuthenticatedUserId));
- if (username == NULL)
- userid = AuthenticatedUserId;
- else
- {
- userid = get_usesysid(username);
- if (userid != AuthenticatedUserId &&
- !AuthenticatedUserIsSuperuser)
- elog(ERROR, "permission denied");
- }
+ if (userid != AuthenticatedUserId &&
+ !AuthenticatedUserIsSuperuser)
+ elog(ERROR, "permission denied");
SetSessionUserId(userid);
SetUserId(userid);
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 95974c6d6a..817c87c80a 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.104 2002/05/05 00:03:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.105 2002/05/17 01:19:18 tgl Exp $
*
*
*-------------------------------------------------------------------------
@@ -28,7 +28,6 @@
#include "catalog/pg_database.h"
#include "catalog/pg_shadow.h"
#include "commands/trigger.h"
-#include "commands/variable.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "storage/backendid.h"
@@ -132,6 +131,9 @@ ReverifyMyDatabase(const char *name)
*/
#ifdef MULTIBYTE
SetDatabaseEncoding(dbform->encoding);
+ /* If we have no other source of client_encoding, use server encoding */
+ SetConfigOption("client_encoding", GetDatabaseEncodingName(),
+ PGC_BACKEND, PGC_S_DEFAULT);
#else
if (dbform->encoding != PG_SQL_ASCII)
elog(FATAL, "database was initialized with MULTIBYTE encoding %d,\n\tbut the backend was compiled without multibyte support.\n\tlooks like you need to initdb or recompile.",
@@ -388,11 +390,6 @@ InitPostgres(const char *dbname, const char *username)
/* set default namespace search path */
InitializeSearchPath();
-#ifdef MULTIBYTE
- /* set default client encoding --- uses info from ReverifyMyDatabase */
- set_default_client_encoding();
-#endif
-
/*
* Set up process-exit callback to do pre-shutdown cleanup. This should
* be last because we want shmem_exit to call this routine before the exit
diff --git a/src/backend/utils/misc/README b/src/backend/utils/misc/README
new file mode 100644
index 0000000000..fe252d534d
--- /dev/null
+++ b/src/backend/utils/misc/README
@@ -0,0 +1,136 @@
+$Header: /cvsroot/pgsql/src/backend/utils/misc/README,v 1.1 2002/05/17 01:19:18 tgl Exp $
+
+
+GUC IMPLEMENTATION NOTES
+
+The GUC (Grand Unified Configuration) module implements configuration
+variables of multiple types (currently boolean, int, float, and string).
+Variable settings can come from various places, with a priority ordering
+determining which setting is used.
+
+
+PER-VARIABLE HOOKS
+
+Each variable known to GUC can optionally have an assign_hook and/or
+a show_hook to provide customized behavior. Assign hooks are used to
+perform validity checking on variable values (above and beyond what
+GUC can do). They are also used to update any derived state that needs
+to change when a GUC variable is set. Show hooks are used to modify
+the default SHOW display for a variable.
+
+If an assign_hook is provided, it points to a function of the signature
+ bool assign_hook(newvalue, bool doit, bool interactive)
+where the type of 'newvalue' matches the kind of variable. This function
+is called immediately before actually setting the variable's value (so it
+can look at the actual variable to determine the old value). If the
+function returns "true" then the assignment is completed; if it returns
+"false" then newvalue is considered invalid and the assignment is not
+performed. If "doit" is false then the function should simply check
+validity of newvalue and not change any derived state. "interactive" is
+true when we are performing a SET command; in this case it is okay for the
+assign_hook to raise an error via elog(). If the function returns false
+for an interactive assignment then guc.c will report a generic "invalid
+value" error message. (An internal elog() in an assign_hook is only
+needed if you want to generate a specialized error message.) But when
+"interactive" is false we are reading a non-interactive option source,
+such as postgresql.conf. In this case the assign_hook should *not* elog
+but should just return false if it doesn't like the newvalue. (An
+elog(LOG) call would be acceptable if you feel a need for a custom
+complaint in this situation.)
+
+For string variables, the signature for assign hooks is a bit different:
+ const char *assign_hook(const char *newvalue,
+ bool doit,
+ bool interactive)
+The meanings of the parameters are the same as for the other types of GUC
+variables, but the return value is handled differently:
+ NULL --- assignment fails (like returning false for other datatypes)
+ newvalue --- assignment succeeds, assign the newvalue as-is
+ malloc'd (not palloc'd!!!) string --- assign that value instead
+The third choice is allowed in case the assign_hook wants to return a
+"canonical" version of the new value. For example, the assign_hook for
+datestyle always returns a string that includes both basic datestyle and
+us/euro option, although the input might have specified only one.
+
+If a show_hook is provided, it points to a function of the signature
+ const char *show_hook(void)
+This hook allows variable-specific computation of the value displayed
+by SHOW.
+
+
+SAVING/RESTORING GUC VARIABLE VALUES
+
+Prior values of configuration variables must be remembered in order to
+deal with three special cases: RESET (a/k/a SET TO DEFAULT), rollback of
+SET on transaction abort, and rollback of SET LOCAL at transaction end
+(either commit or abort). RESET is defined as selecting the value that
+would be effective had there never been any SET commands in the current
+session.
+
+To handle these cases we must keep track of as many as four distinct
+values for each variable. They are:
+
+* actual variable contents always the current effective value
+
+* reset_value the value to use for RESET
+
+* session_value the "committed" setting for the session
+
+* tentative_value the uncommitted result of SET
+
+During initialization we set the first three of these (actual, reset_value,
+and session_value) based on whichever non-interactive source has the
+highest priority. All three will have the same value.
+
+A SET LOCAL command sets the actual variable (and nothing else). At
+transaction end, the session_value is used to restore the actual variable
+to its pre-transaction value.
+
+A SET (or SET SESSION) command sets the actual variable, and if no error,
+then sets the tentative_value. If the transaction commits, the
+tentative_value is assigned to the session_value and the actual variable
+(which could by now be different, if the SET was followed by SET LOCAL).
+If the transaction aborts, the tentative_value is discarded and the
+actual variable is restored from the session_value.
+
+RESET is executed like a SET, but using the reset_value as the desired new
+value. (We do not provide a RESET LOCAL command, but SET LOCAL TO DEFAULT
+has the same behavior that RESET LOCAL would.) The source associated with
+the reset_value also becomes associated with the actual and session values.
+
+If SIGHUP is received, the GUC code rereads the postgresql.conf
+configuration file (this does not happen in the signal handler, but at
+next return to main loop; note that it can be executed while within a
+transaction). New values from postgresql.conf are assigned to actual
+variable, reset_value, and session_value, but only if each of these has a
+current source priority <= PGC_S_FILE. (It is thus possible for
+reset_value to track the config-file setting even if there is currently
+a different interactive value of the actual variable.)
+
+Note that tentative_value is unused and undefined except between a SET
+command and the end of the transaction. Also notice that we must track
+the source associated with each of the four values.
+
+The assign_hook and show_hook routines work only with the actual variable,
+and are not directly aware of the additional values maintained by GUC.
+This is not a problem for normal usage, since we can assign first to the
+actual variable and then (if that succeeds) to the additional values as
+needed. However, for SIGHUP rereads we may not want to assign to the
+actual variable. Our procedure in that case is to call the assign_hook
+with doit = false so that the value is validated, but no derived state is
+changed.
+
+
+STRING MEMORY HANDLING
+
+String option values are allocated with strdup, not with the
+pstrdup/palloc mechanisms. We would need to keep them in a permanent
+context anyway, and strdup gives us more control over handling
+out-of-memory failures.
+
+We allow a variable's actual value, reset_val, session_val, and
+tentative_val to point at the same storage. This makes it slightly harder
+to free space (must test that the value to be freed isn't equal to any of
+the other three pointers). The main advantage is that we never need to
+strdup during transaction commit/abort, so cannot cause an out-of-memory
+failure there.
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index fe6cf89ac0..2f50b4b55c 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -4,7 +4,7 @@
*
* Copyright 2000 by PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v 1.11 2002/03/02 21:39:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc-file.l,v 1.12 2002/05/17 01:19:18 tgl Exp $
*/
%{
@@ -168,7 +168,7 @@ ProcessConfigFile(GucContext context)
head = tail = NULL;
opt_name = opt_value = NULL;
- while((token = yylex()))
+ while ((token = yylex()))
switch(parse_state)
{
case 0: /* no previous input */
@@ -188,23 +188,22 @@ ProcessConfigFile(GucContext context)
token = yylex();
if (token != GUC_ID && token != GUC_STRING &&
- token != GUC_INTEGER && token != GUC_REAL &&
- token != GUC_UNQUOTED_STRING)
+ token != GUC_INTEGER && token != GUC_REAL &&
+ token != GUC_UNQUOTED_STRING)
goto parse_error;
opt_value = strdup(yytext);
if (opt_value == NULL)
goto out_of_memory;
- if (token == GUC_STRING)
- {
- /* remove the beginning and ending quote/apostrophe */
- /* first: shift the whole shooting match down one
- character */
- memmove(opt_value,opt_value+1,strlen(opt_value)-1);
- /* second: null out the 2 characters we shifted */
- opt_value[strlen(opt_value)-2]='\0';
- /* do the escape thing. free()'s the strdup above */
- opt_value=GUC_scanstr(opt_value);
- }
+ if (token == GUC_STRING)
+ {
+ /* remove the beginning and ending quote/apostrophe */
+ /* first: shift the whole thing down one character */
+ memmove(opt_value,opt_value+1,strlen(opt_value)-1);
+ /* second: null out the 2 characters we shifted */
+ opt_value[strlen(opt_value)-2]='\0';
+ /* do the escape thing. free()'s the strdup above */
+ opt_value=GUC_scanstr(opt_value);
+ }
parse_state = 2;
break;
@@ -241,14 +240,14 @@ ProcessConfigFile(GucContext context)
for(item = head; item; item=item->next)
{
if (!set_config_option(item->name, item->value, context,
- false, PGC_S_INFINITY))
+ PGC_S_FILE, false, false))
goto cleanup_exit;
}
/* If we got here all the options parsed okay. */
for(item = head; item; item=item->next)
set_config_option(item->name, item->value, context,
- true, PGC_S_FILE);
+ PGC_S_FILE, false, true);
cleanup_exit:
free_name_value_list(head);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f917af9a42..f1d4e8ee29 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3,8 +3,9 @@
*
* Support for grand unified configuration scheme, including SET
* command, configuration file, and command line options.
+ * See src/backend/utils/misc/README for more information.
*
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.67 2002/05/14 13:05:43 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.68 2002/05/17 01:19:18 tgl Exp $
*
* Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut .
@@ -23,6 +24,7 @@
#include "access/xlog.h"
#include "catalog/namespace.h"
#include "commands/async.h"
+#include "commands/variable.h"
#include "fmgr.h"
#include "libpq/auth.h"
#include "libpq/pqcomm.h"
@@ -57,14 +59,11 @@ extern bool FixBTree;
#ifdef HAVE_SYSLOG
extern char *Syslog_facility;
extern char *Syslog_ident;
-static bool check_facility(const char *facility);
+
+static const char *assign_facility(const char *facility,
+ bool doit, bool interactive);
#endif
-static char *default_iso_level_string;
-
-static bool check_defaultxactisolevel(const char *value);
-static void assign_defaultxactisolevel(const char *value);
-
/*
* Debugging options
*/
@@ -96,87 +95,167 @@ bool Password_encryption = false;
#define PG_KRB_SRVTAB ""
#endif
-static bool guc_session_init = false; /* XXX mildly bogus */
+/*
+ * These variables are all dummies that don't do anything, except in some
+ * cases provide the value for SHOW to display. The real state is elsewhere
+ * and is kept in sync by assign_hooks.
+ */
+static double phony_random_seed;
+static char *client_encoding_string;
+static char *datestyle_string;
+static char *default_iso_level_string;
+static char *server_encoding_string;
+static char *session_authorization_string;
+static char *timezone_string;
+static char *XactIsoLevel_string;
+
+static const char *assign_defaultxactisolevel(const char *newval,
+ bool doit, bool interactive);
+
/*
* Declarations for GUC tables
+ *
+ * See src/backend/utils/misc/README for design notes.
*/
enum config_type
{
- PGC_NONE = 0,
PGC_BOOL,
PGC_INT,
PGC_REAL,
PGC_STRING
};
-
+/* Generic fields applicable to all types of variables */
struct config_generic
{
- const char *name;
- GucContext context;
- GucSource source;
- void *variable;
+ /* constant fields, must be set correctly in initial value: */
+ const char *name; /* name of variable - MUST BE FIRST */
+ GucContext context; /* context required to set the variable */
+ int flags; /* flag bits, see below */
+ /* variable fields, initialized at runtime: */
+ enum config_type vartype; /* type of variable (set only at startup) */
+ int status; /* status bits, see below */
+ GucSource reset_source; /* source of the reset_value */
+ GucSource session_source; /* source of the session_value */
+ GucSource tentative_source; /* source of the tentative_value */
+ GucSource source; /* source of the current actual value */
};
+/* bit values in flags field */
+#define GUC_LIST_INPUT 0x0001 /* input can be list format */
+#define GUC_LIST_QUOTE 0x0002 /* double-quote list elements */
+#define GUC_NO_SHOW_ALL 0x0004 /* exclude from SHOW ALL */
+#define GUC_NO_RESET_ALL 0x0008 /* exclude from RESET ALL */
+
+/* bit values in status field */
+#define GUC_HAVE_TENTATIVE 0x0001 /* tentative value is defined */
+#define GUC_HAVE_LOCAL 0x0002 /* a SET LOCAL has been executed */
+
+
+/* GUC records for specific variable types */
struct config_bool
{
- const char *name;
- GucContext context;
- GucSource source;
+ struct config_generic gen;
+ /* these fields must be set correctly in initial value: */
+ /* (all but reset_val are constants) */
bool *variable;
- bool default_val;
- /* No need for parse_hook ... presumably both values are legal */
- void (*assign_hook) (bool newval);
+ bool reset_val;
+ bool (*assign_hook) (bool newval, bool doit, bool interactive);
+ const char *(*show_hook) (void);
+ /* variable fields, initialized at runtime: */
+ bool session_val;
+ bool tentative_val;
};
-
struct config_int
{
- const char *name;
- GucContext context;
- GucSource source;
+ struct config_generic gen;
+ /* these fields must be set correctly in initial value: */
+ /* (all but reset_val are constants) */
int *variable;
- int default_val;
+ int reset_val;
int min;
int max;
- bool (*parse_hook) (int proposed);
- void (*assign_hook) (int newval);
+ bool (*assign_hook) (int newval, bool doit, bool interactive);
+ const char *(*show_hook) (void);
+ /* variable fields, initialized at runtime: */
+ int session_val;
+ int tentative_val;
};
-
struct config_real
{
- const char *name;
- GucContext context;
- GucSource source;
+ struct config_generic gen;
+ /* these fields must be set correctly in initial value: */
+ /* (all but reset_val are constants) */
double *variable;
- double default_val;
+ double reset_val;
double min;
double max;
- bool (*parse_hook) (double proposed);
- void (*assign_hook) (double newval);
+ bool (*assign_hook) (double newval, bool doit, bool interactive);
+ const char *(*show_hook) (void);
+ /* variable fields, initialized at runtime: */
+ double session_val;
+ double tentative_val;
};
-/*
- * String value options are allocated with strdup, not with the
- * pstrdup/palloc mechanisms. That is because configuration settings
- * are already in place before the memory subsystem is up. It would
- * perhaps be an idea to change that sometime.
- */
struct config_string
{
- const char *name;
- GucContext context;
- GucSource source;
+ struct config_generic gen;
+ /* these fields must be set correctly in initial value: */
+ /* (all are constants) */
char **variable;
- const char *boot_default_val;
- bool (*parse_hook) (const char *proposed);
- void (*assign_hook) (const char *newval);
- char *default_val;
+ const char *boot_val;
+ const char *(*assign_hook) (const char *newval, bool doit, bool interactive);
+ const char *(*show_hook) (void);
+ /* variable fields, initialized at runtime: */
+ char *reset_val;
+ char *session_val;
+ char *tentative_val;
};
+/* Macros for freeing malloc'd pointers only if appropriate to do so */
+/* Some of these tests are probably redundant, but be safe ... */
+#define SET_STRING_VARIABLE(rec, newval) \
+ do { \
+ if (*(rec)->variable && \
+ *(rec)->variable != (rec)->reset_val && \
+ *(rec)->variable != (rec)->session_val && \
+ *(rec)->variable != (rec)->tentative_val) \
+ free(*(rec)->variable); \
+ *(rec)->variable = (newval); \
+ } while (0)
+#define SET_STRING_RESET_VAL(rec, newval) \
+ do { \
+ if ((rec)->reset_val && \
+ (rec)->reset_val != *(rec)->variable && \
+ (rec)->reset_val != (rec)->session_val && \
+ (rec)->reset_val != (rec)->tentative_val) \
+ free((rec)->reset_val); \
+ (rec)->reset_val = (newval); \
+ } while (0)
+#define SET_STRING_SESSION_VAL(rec, newval) \
+ do { \
+ if ((rec)->session_val && \
+ (rec)->session_val != *(rec)->variable && \
+ (rec)->session_val != (rec)->reset_val && \
+ (rec)->session_val != (rec)->tentative_val) \
+ free((rec)->session_val); \
+ (rec)->session_val = (newval); \
+ } while (0)
+#define SET_STRING_TENTATIVE_VAL(rec, newval) \
+ do { \
+ if ((rec)->tentative_val && \
+ (rec)->tentative_val != *(rec)->variable && \
+ (rec)->tentative_val != (rec)->reset_val && \
+ (rec)->tentative_val != (rec)->session_val) \
+ free((rec)->tentative_val); \
+ (rec)->tentative_val = (newval); \
+ } while (0)
+
+
/*
* TO ADD AN OPTION:
@@ -200,167 +279,212 @@ struct config_string
*/
-/******** option names follow ********/
+/******** option records follow ********/
static struct config_bool
ConfigureNamesBool[] =
{
{
- "enable_seqscan", PGC_USERSET, PGC_S_DEFAULT, &enable_seqscan, true, NULL
+ { "enable_seqscan", PGC_USERSET }, &enable_seqscan,
+ true, NULL, NULL
},
{
- "enable_indexscan", PGC_USERSET, PGC_S_DEFAULT, &enable_indexscan, true, NULL
+ { "enable_indexscan", PGC_USERSET }, &enable_indexscan,
+ true, NULL, NULL
},
{
- "enable_tidscan", PGC_USERSET, PGC_S_DEFAULT, &enable_tidscan, true, NULL
+ { "enable_tidscan", PGC_USERSET }, &enable_tidscan,
+ true, NULL, NULL
},
{
- "enable_sort", PGC_USERSET, PGC_S_DEFAULT, &enable_sort, true, NULL
+ { "enable_sort", PGC_USERSET }, &enable_sort,
+ true, NULL, NULL
},
{
- "enable_nestloop", PGC_USERSET, PGC_S_DEFAULT, &enable_nestloop, true, NULL
+ { "enable_nestloop", PGC_USERSET }, &enable_nestloop,
+ true, NULL, NULL
},
{
- "enable_mergejoin", PGC_USERSET, PGC_S_DEFAULT, &enable_mergejoin, true, NULL
+ { "enable_mergejoin", PGC_USERSET }, &enable_mergejoin,
+ true, NULL, NULL
},
{
- "enable_hashjoin", PGC_USERSET, PGC_S_DEFAULT, &enable_hashjoin, true, NULL
+ { "enable_hashjoin", PGC_USERSET }, &enable_hashjoin,
+ true, NULL, NULL
},
{
- "ksqo", PGC_USERSET, PGC_S_DEFAULT, &_use_keyset_query_optimizer, false, NULL
+ { "ksqo", PGC_USERSET }, &_use_keyset_query_optimizer,
+ false, NULL, NULL
},
{
- "geqo", PGC_USERSET, PGC_S_DEFAULT, &enable_geqo, true, NULL
+ { "geqo", PGC_USERSET }, &enable_geqo,
+ true, NULL, NULL
},
{
- "tcpip_socket", PGC_POSTMASTER, PGC_S_DEFAULT, &NetServer, false, NULL
+ { "tcpip_socket", PGC_POSTMASTER }, &NetServer,
+ false, NULL, NULL
},
{
- "ssl", PGC_POSTMASTER, PGC_S_DEFAULT, &EnableSSL, false, NULL
+ { "ssl", PGC_POSTMASTER }, &EnableSSL,
+ false, NULL, NULL
},
{
- "fsync", PGC_SIGHUP, PGC_S_DEFAULT, &enableFsync, true, NULL
+ { "fsync", PGC_SIGHUP }, &enableFsync,
+ true, NULL, NULL
},
{
- "silent_mode", PGC_POSTMASTER, PGC_S_DEFAULT, &SilentMode, false, NULL
+ { "silent_mode", PGC_POSTMASTER }, &SilentMode,
+ false, NULL, NULL
},
{
- "log_connections", PGC_BACKEND, PGC_S_DEFAULT, &Log_connections, false, NULL
+ { "log_connections", PGC_BACKEND }, &Log_connections,
+ false, NULL, NULL
},
{
- "log_timestamp", PGC_SIGHUP, PGC_S_DEFAULT, &Log_timestamp, false, NULL
+ { "log_timestamp", PGC_SIGHUP }, &Log_timestamp,
+ false, NULL, NULL
},
{
- "log_pid", PGC_SIGHUP, PGC_S_DEFAULT, &Log_pid, false, NULL
+ { "log_pid", PGC_SIGHUP }, &Log_pid,
+ false, NULL, NULL
},
#ifdef USE_ASSERT_CHECKING
{
- "debug_assertions", PGC_USERSET, PGC_S_DEFAULT, &assert_enabled, true, NULL
+ { "debug_assertions", PGC_USERSET }, &assert_enabled,
+ true, NULL, NULL
},
#endif
{
- "debug_print_query", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_query, false, NULL
+ { "debug_print_query", PGC_USERSET }, &Debug_print_query,
+ false, NULL, NULL
},
{
- "debug_print_parse", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_parse, false, NULL
+ { "debug_print_parse", PGC_USERSET }, &Debug_print_parse,
+ false, NULL, NULL
},
{
- "debug_print_rewritten", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_rewritten, false, NULL
+ { "debug_print_rewritten", PGC_USERSET }, &Debug_print_rewritten,
+ false, NULL, NULL
},
{
- "debug_print_plan", PGC_USERSET, PGC_S_DEFAULT, &Debug_print_plan, false, NULL
+ { "debug_print_plan", PGC_USERSET }, &Debug_print_plan,
+ false, NULL, NULL
},
{
- "debug_pretty_print", PGC_USERSET, PGC_S_DEFAULT, &Debug_pretty_print, false, NULL
+ { "debug_pretty_print", PGC_USERSET }, &Debug_pretty_print,
+ false, NULL, NULL
},
{
- "show_parser_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_parser_stats, false, NULL
+ { "show_parser_stats", PGC_USERSET }, &Show_parser_stats,
+ false, NULL, NULL
},
{
- "show_planner_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_planner_stats, false, NULL
+ { "show_planner_stats", PGC_USERSET }, &Show_planner_stats,
+ false, NULL, NULL
},
{
- "show_executor_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_executor_stats, false, NULL
+ { "show_executor_stats", PGC_USERSET }, &Show_executor_stats,
+ false, NULL, NULL
},
{
- "show_query_stats", PGC_USERSET, PGC_S_DEFAULT, &Show_query_stats, false, NULL
+ { "show_query_stats", PGC_USERSET }, &Show_query_stats,
+ false, NULL, NULL
},
#ifdef BTREE_BUILD_STATS
{
- "show_btree_build_stats", PGC_SUSET, PGC_S_DEFAULT, &Show_btree_build_stats, false, NULL
+ { "show_btree_build_stats", PGC_SUSET }, &Show_btree_build_stats,
+ false, NULL, NULL
},
#endif
{
- "explain_pretty_print", PGC_USERSET, PGC_S_DEFAULT, &Explain_pretty_print, true, NULL
+ { "explain_pretty_print", PGC_USERSET }, &Explain_pretty_print,
+ true, NULL, NULL
},
{
- "stats_start_collector", PGC_POSTMASTER, PGC_S_DEFAULT, &pgstat_collect_startcollector, true, NULL
+ { "stats_start_collector", PGC_POSTMASTER }, &pgstat_collect_startcollector,
+ true, NULL, NULL
},
{
- "stats_reset_on_server_start", PGC_POSTMASTER, PGC_S_DEFAULT, &pgstat_collect_resetonpmstart, true, NULL
+ { "stats_reset_on_server_start", PGC_POSTMASTER }, &pgstat_collect_resetonpmstart,
+ true, NULL, NULL
},
{
- "stats_command_string", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_querystring, false, NULL
+ { "stats_command_string", PGC_SUSET }, &pgstat_collect_querystring,
+ false, NULL, NULL
},
{
- "stats_row_level", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_tuplelevel, false, NULL
+ { "stats_row_level", PGC_SUSET }, &pgstat_collect_tuplelevel,
+ false, NULL, NULL
},
{
- "stats_block_level", PGC_SUSET, PGC_S_DEFAULT, &pgstat_collect_blocklevel, false, NULL
+ { "stats_block_level", PGC_SUSET }, &pgstat_collect_blocklevel,
+ false, NULL, NULL
},
{
- "trace_notify", PGC_USERSET, PGC_S_DEFAULT, &Trace_notify, false, NULL
+ { "trace_notify", PGC_USERSET }, &Trace_notify,
+ false, NULL, NULL
},
#ifdef LOCK_DEBUG
{
- "trace_locks", PGC_SUSET, PGC_S_DEFAULT, &Trace_locks, false, NULL
+ { "trace_locks", PGC_SUSET }, &Trace_locks,
+ false, NULL, NULL
},
{
- "trace_userlocks", PGC_SUSET, PGC_S_DEFAULT, &Trace_userlocks, false, NULL
+ { "trace_userlocks", PGC_SUSET }, &Trace_userlocks,
+ false, NULL, NULL
},
{
- "trace_lwlocks", PGC_SUSET, PGC_S_DEFAULT, &Trace_lwlocks, false, NULL
+ { "trace_lwlocks", PGC_SUSET }, &Trace_lwlocks,
+ false, NULL, NULL
},
{
- "debug_deadlocks", PGC_SUSET, PGC_S_DEFAULT, &Debug_deadlocks, false, NULL
+ { "debug_deadlocks", PGC_SUSET }, &Debug_deadlocks,
+ false, NULL, NULL
},
#endif
{
- "hostname_lookup", PGC_SIGHUP, PGC_S_DEFAULT, &HostnameLookup, false, NULL
+ { "hostname_lookup", PGC_SIGHUP }, &HostnameLookup,
+ false, NULL, NULL
},
{
- "show_source_port", PGC_SIGHUP, PGC_S_DEFAULT, &ShowPortNumber, false, NULL
+ { "show_source_port", PGC_SIGHUP }, &ShowPortNumber,
+ false, NULL, NULL
},
{
- "sql_inheritance", PGC_USERSET, PGC_S_DEFAULT, &SQL_inheritance, true, NULL
+ { "sql_inheritance", PGC_USERSET }, &SQL_inheritance,
+ true, NULL, NULL
},
{
- "australian_timezones", PGC_USERSET, PGC_S_DEFAULT, &Australian_timezones, false, ClearDateCache
+ { "australian_timezones", PGC_USERSET }, &Australian_timezones,
+ false, ClearDateCache, NULL
},
{
- "fixbtree", PGC_POSTMASTER, PGC_S_DEFAULT, &FixBTree, true, NULL
+ { "fixbtree", PGC_POSTMASTER }, &FixBTree,
+ true, NULL, NULL
},
{
- "password_encryption", PGC_USERSET, PGC_S_DEFAULT, &Password_encryption, false, NULL
+ { "password_encryption", PGC_USERSET }, &Password_encryption,
+ false, NULL, NULL
},
{
- "transform_null_equals", PGC_USERSET, PGC_S_DEFAULT, &Transform_null_equals, false, NULL
+ { "transform_null_equals", PGC_USERSET }, &Transform_null_equals,
+ false, NULL, NULL
},
{
- NULL, 0, 0, NULL, false, NULL
+ { NULL, 0 }, NULL, false, NULL, NULL
}
};
@@ -369,34 +493,34 @@ static struct config_int
ConfigureNamesInt[] =
{
{
- "geqo_threshold", PGC_USERSET, PGC_S_DEFAULT, &geqo_rels,
+ { "geqo_threshold", PGC_USERSET }, &geqo_rels,
DEFAULT_GEQO_RELS, 2, INT_MAX, NULL, NULL
},
{
- "geqo_pool_size", PGC_USERSET, PGC_S_DEFAULT, &Geqo_pool_size,
+ { "geqo_pool_size", PGC_USERSET }, &Geqo_pool_size,
DEFAULT_GEQO_POOL_SIZE, 0, MAX_GEQO_POOL_SIZE, NULL, NULL
},
{
- "geqo_effort", PGC_USERSET, PGC_S_DEFAULT, &Geqo_effort,
+ { "geqo_effort", PGC_USERSET }, &Geqo_effort,
1, 1, INT_MAX, NULL, NULL
},
{
- "geqo_generations", PGC_USERSET, PGC_S_DEFAULT, &Geqo_generations,
+ { "geqo_generations", PGC_USERSET }, &Geqo_generations,
0, 0, INT_MAX, NULL, NULL
},
{
- "geqo_random_seed", PGC_USERSET, PGC_S_DEFAULT, &Geqo_random_seed,
+ { "geqo_random_seed", PGC_USERSET }, &Geqo_random_seed,
-1, INT_MIN, INT_MAX, NULL, NULL
},
{
- "deadlock_timeout", PGC_POSTMASTER, PGC_S_DEFAULT, &DeadlockTimeout,
+ { "deadlock_timeout", PGC_POSTMASTER }, &DeadlockTimeout,
1000, 0, INT_MAX, NULL, NULL
},
#ifdef HAVE_SYSLOG
{
- "syslog", PGC_SIGHUP, PGC_S_DEFAULT, &Use_syslog,
+ { "syslog", PGC_SIGHUP }, &Use_syslog,
0, 0, 2, NULL, NULL
},
#endif
@@ -407,116 +531,116 @@ static struct config_int
* constraints here are partially unused.
*/
{
- "max_connections", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxBackends,
+ { "max_connections", PGC_POSTMASTER }, &MaxBackends,
DEF_MAXBACKENDS, 1, INT_MAX, NULL, NULL
},
{
- "shared_buffers", PGC_POSTMASTER, PGC_S_DEFAULT, &NBuffers,
+ { "shared_buffers", PGC_POSTMASTER }, &NBuffers,
DEF_NBUFFERS, 16, INT_MAX, NULL, NULL
},
{
- "port", PGC_POSTMASTER, PGC_S_DEFAULT, &PostPortNumber,
+ { "port", PGC_POSTMASTER }, &PostPortNumber,
DEF_PGPORT, 1, 65535, NULL, NULL
},
{
- "unix_socket_permissions", PGC_POSTMASTER, PGC_S_DEFAULT, &Unix_socket_permissions,
+ { "unix_socket_permissions", PGC_POSTMASTER }, &Unix_socket_permissions,
0777, 0000, 0777, NULL, NULL
},
{
- "sort_mem", PGC_USERSET, PGC_S_DEFAULT, &SortMem,
+ { "sort_mem", PGC_USERSET }, &SortMem,
512, 4 * BLCKSZ / 1024, INT_MAX, NULL, NULL
},
{
- "vacuum_mem", PGC_USERSET, PGC_S_DEFAULT, &VacuumMem,
+ { "vacuum_mem", PGC_USERSET }, &VacuumMem,
8192, 1024, INT_MAX, NULL, NULL
},
{
- "max_files_per_process", PGC_BACKEND, PGC_S_DEFAULT, &max_files_per_process,
+ { "max_files_per_process", PGC_BACKEND }, &max_files_per_process,
1000, 25, INT_MAX, NULL, NULL
},
#ifdef LOCK_DEBUG
{
- "trace_lock_oidmin", PGC_SUSET, PGC_S_DEFAULT, &Trace_lock_oidmin,
+ { "trace_lock_oidmin", PGC_SUSET }, &Trace_lock_oidmin,
BootstrapObjectIdData, 1, INT_MAX, NULL, NULL
},
{
- "trace_lock_table", PGC_SUSET, PGC_S_DEFAULT, &Trace_lock_table,
+ { "trace_lock_table", PGC_SUSET }, &Trace_lock_table,
0, 0, INT_MAX, NULL, NULL
},
#endif
{
- "max_expr_depth", PGC_USERSET, PGC_S_DEFAULT, &max_expr_depth,
+ { "max_expr_depth", PGC_USERSET }, &max_expr_depth,
DEFAULT_MAX_EXPR_DEPTH, 10, INT_MAX, NULL, NULL
},
{
- "max_fsm_relations", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxFSMRelations,
+ { "max_fsm_relations", PGC_POSTMASTER }, &MaxFSMRelations,
100, 10, INT_MAX, NULL, NULL
},
{
- "max_fsm_pages", PGC_POSTMASTER, PGC_S_DEFAULT, &MaxFSMPages,
+ { "max_fsm_pages", PGC_POSTMASTER }, &MaxFSMPages,
10000, 1000, INT_MAX, NULL, NULL
},
{
- "max_locks_per_transaction", PGC_POSTMASTER, PGC_S_DEFAULT, &max_locks_per_xact,
+ { "max_locks_per_transaction", PGC_POSTMASTER }, &max_locks_per_xact,
64, 10, INT_MAX, NULL, NULL
},
{
- "authentication_timeout", PGC_SIGHUP, PGC_S_DEFAULT, &AuthenticationTimeout,
+ { "authentication_timeout", PGC_SIGHUP }, &AuthenticationTimeout,
60, 1, 600, NULL, NULL
},
{
- "pre_auth_delay", PGC_SIGHUP, PGC_S_DEFAULT, &PreAuthDelay,
+ { "pre_auth_delay", PGC_SIGHUP }, &PreAuthDelay,
0, 0, 60, NULL, NULL
},
{
- "checkpoint_segments", PGC_SIGHUP, PGC_S_DEFAULT, &CheckPointSegments,
+ { "checkpoint_segments", PGC_SIGHUP }, &CheckPointSegments,
3, 1, INT_MAX, NULL, NULL
},
{
- "checkpoint_timeout", PGC_SIGHUP, PGC_S_DEFAULT, &CheckPointTimeout,
+ { "checkpoint_timeout", PGC_SIGHUP }, &CheckPointTimeout,
300, 30, 3600, NULL, NULL
},
{
- "wal_buffers", PGC_POSTMASTER, PGC_S_DEFAULT, &XLOGbuffers,
+ { "wal_buffers", PGC_POSTMASTER }, &XLOGbuffers,
8, 4, INT_MAX, NULL, NULL
},
{
- "wal_files", PGC_SIGHUP, PGC_S_DEFAULT, &XLOGfiles,
+ { "wal_files", PGC_SIGHUP }, &XLOGfiles,
0, 0, 64, NULL, NULL
},
{
- "wal_debug", PGC_SUSET, PGC_S_DEFAULT, &XLOG_DEBUG,
+ { "wal_debug", PGC_SUSET }, &XLOG_DEBUG,
0, 0, 16, NULL, NULL
},
{
- "commit_delay", PGC_USERSET, PGC_S_DEFAULT, &CommitDelay,
+ { "commit_delay", PGC_USERSET }, &CommitDelay,
0, 0, 100000, NULL, NULL
},
{
- "commit_siblings", PGC_USERSET, PGC_S_DEFAULT, &CommitSiblings,
+ { "commit_siblings", PGC_USERSET }, &CommitSiblings,
5, 1, 1000, NULL, NULL
},
{
- NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL
+ { NULL, 0 }, NULL, 0, 0, 0, NULL, NULL
}
};
@@ -525,34 +649,40 @@ static struct config_real
ConfigureNamesReal[] =
{
{
- "effective_cache_size", PGC_USERSET, PGC_S_DEFAULT, &effective_cache_size,
+ { "effective_cache_size", PGC_USERSET }, &effective_cache_size,
DEFAULT_EFFECTIVE_CACHE_SIZE, 0, DBL_MAX, NULL, NULL
},
{
- "random_page_cost", PGC_USERSET, PGC_S_DEFAULT, &random_page_cost,
+ { "random_page_cost", PGC_USERSET }, &random_page_cost,
DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, NULL, NULL
},
{
- "cpu_tuple_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_tuple_cost,
+ { "cpu_tuple_cost", PGC_USERSET }, &cpu_tuple_cost,
DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, NULL, NULL
},
{
- "cpu_index_tuple_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_index_tuple_cost,
+ { "cpu_index_tuple_cost", PGC_USERSET }, &cpu_index_tuple_cost,
DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, NULL, NULL
},
{
- "cpu_operator_cost", PGC_USERSET, PGC_S_DEFAULT, &cpu_operator_cost,
+ { "cpu_operator_cost", PGC_USERSET }, &cpu_operator_cost,
DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, NULL, NULL
},
{
- "geqo_selection_bias", PGC_USERSET, PGC_S_DEFAULT, &Geqo_selection_bias,
+ { "geqo_selection_bias", PGC_USERSET }, &Geqo_selection_bias,
DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS,
MAX_GEQO_SELECTION_BIAS, NULL, NULL
},
{
- NULL, 0, 0, NULL, 0.0, 0.0, 0.0, NULL, NULL
+ { "seed", PGC_USERSET, GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL },
+ &phony_random_seed,
+ 0.5, 0.0, 1.0, assign_random_seed, show_random_seed
+ },
+
+ {
+ { NULL, 0 }, NULL, 0.0, 0.0, 0.0, NULL, NULL
}
};
@@ -561,229 +691,710 @@ static struct config_string
ConfigureNamesString[] =
{
{
- "client_min_messages", PGC_USERSET, PGC_S_DEFAULT, &client_min_messages_str,
- client_min_messages_str_default, check_client_min_messages,
- assign_client_min_messages
+ { "client_encoding", PGC_USERSET }, &client_encoding_string,
+ "SQL_ASCII", assign_client_encoding, NULL
},
{
- "default_transaction_isolation", PGC_USERSET, PGC_S_DEFAULT, &default_iso_level_string,
- "read committed", check_defaultxactisolevel, assign_defaultxactisolevel
+ { "client_min_messages", PGC_USERSET }, &client_min_messages_str,
+ client_min_messages_str_default, assign_client_min_messages, NULL
},
{
- "dynamic_library_path", PGC_SUSET, PGC_S_DEFAULT, &Dynamic_library_path,
+ { "DateStyle", PGC_USERSET, GUC_LIST_INPUT }, &datestyle_string,
+ "ISO, US", assign_datestyle, show_datestyle
+ },
+
+ {
+ { "default_transaction_isolation", PGC_USERSET }, &default_iso_level_string,
+ "read committed", assign_defaultxactisolevel, NULL
+ },
+
+ {
+ { "dynamic_library_path", PGC_SUSET }, &Dynamic_library_path,
"$libdir", NULL, NULL
},
{
- "search_path", PGC_USERSET, PGC_S_DEFAULT, &namespace_search_path,
- "$user,public", check_search_path, assign_search_path
- },
-
- {
- "krb_server_keyfile", PGC_POSTMASTER, PGC_S_DEFAULT, &pg_krb_server_keyfile,
+ { "krb_server_keyfile", PGC_POSTMASTER }, &pg_krb_server_keyfile,
PG_KRB_SRVTAB, NULL, NULL
},
{
- "lc_messages", PGC_SUSET, PGC_S_DEFAULT, &locale_messages,
- "", locale_messages_check, locale_messages_assign
+ { "lc_messages", PGC_SUSET }, &locale_messages,
+ "", locale_messages_assign, NULL
},
{
- "lc_monetary", PGC_USERSET, PGC_S_DEFAULT, &locale_monetary,
- "", locale_monetary_check, locale_monetary_assign
+ { "lc_monetary", PGC_USERSET }, &locale_monetary,
+ "", locale_monetary_assign, NULL
},
{
- "lc_numeric", PGC_USERSET, PGC_S_DEFAULT, &locale_numeric,
- "", locale_numeric_check, locale_numeric_assign
+ { "lc_numeric", PGC_USERSET }, &locale_numeric,
+ "", locale_numeric_assign, NULL
},
{
- "lc_time", PGC_USERSET, PGC_S_DEFAULT, &locale_time,
- "", locale_time_check, locale_time_assign
+ { "lc_time", PGC_USERSET }, &locale_time,
+ "", locale_time_assign, NULL
},
{
- "server_min_messages", PGC_USERSET, PGC_S_DEFAULT, &server_min_messages_str,
- server_min_messages_str_default, check_server_min_messages,
- assign_server_min_messages
+ { "search_path", PGC_USERSET, GUC_LIST_INPUT | GUC_LIST_QUOTE },
+ &namespace_search_path,
+ "$user,public", assign_search_path, NULL
+ },
+
+ {
+ { "server_encoding", PGC_USERSET }, &server_encoding_string,
+ "SQL_ASCII", assign_server_encoding, show_server_encoding
+ },
+
+ {
+ { "server_min_messages", PGC_USERSET }, &server_min_messages_str,
+ server_min_messages_str_default, assign_server_min_messages, NULL
+ },
+
+ {
+ { "session_authorization", PGC_USERSET, GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL },
+ &session_authorization_string,
+ NULL, assign_session_authorization, show_session_authorization
},
#ifdef HAVE_SYSLOG
{
- "syslog_facility", PGC_POSTMASTER, PGC_S_DEFAULT, &Syslog_facility,
- "LOCAL0", check_facility, NULL
+ { "syslog_facility", PGC_POSTMASTER }, &Syslog_facility,
+ "LOCAL0", assign_facility, NULL
},
{
- "syslog_ident", PGC_POSTMASTER, PGC_S_DEFAULT, &Syslog_ident,
+ { "syslog_ident", PGC_POSTMASTER }, &Syslog_ident,
"postgres", NULL, NULL
},
#endif
{
- "unix_socket_group", PGC_POSTMASTER, PGC_S_DEFAULT, &Unix_socket_group,
+ { "TimeZone", PGC_USERSET }, &timezone_string,
+ "UNKNOWN", assign_timezone, show_timezone
+ },
+
+ {
+ { "TRANSACTION ISOLATION LEVEL", PGC_USERSET, GUC_NO_RESET_ALL },
+ &XactIsoLevel_string,
+ NULL, assign_XactIsoLevel, show_XactIsoLevel
+ },
+
+ {
+ { "unix_socket_group", PGC_POSTMASTER }, &Unix_socket_group,
"", NULL, NULL
},
{
- "unix_socket_directory", PGC_POSTMASTER, PGC_S_DEFAULT, &UnixSocketDir,
+ { "unix_socket_directory", PGC_POSTMASTER }, &UnixSocketDir,
"", NULL, NULL
},
{
- "virtual_host", PGC_POSTMASTER, PGC_S_DEFAULT, &VirtualHost,
+ { "virtual_host", PGC_POSTMASTER }, &VirtualHost,
"", NULL, NULL
},
{
- "wal_sync_method", PGC_SIGHUP, PGC_S_DEFAULT, &XLOG_sync_method,
- XLOG_sync_method_default, check_xlog_sync_method,
- assign_xlog_sync_method
+ { "wal_sync_method", PGC_SIGHUP }, &XLOG_sync_method,
+ XLOG_sync_method_default, assign_xlog_sync_method, NULL
},
{
- NULL, 0, 0, NULL, NULL, NULL, NULL
+ { NULL, 0 }, NULL, NULL, NULL, NULL
}
};
/******** end of options list ********/
-
/*
- * Look up option NAME. If it exists, return it's data type, else
- * PGC_NONE (zero). If record is not NULL, store the description of
- * the option there.
+ * Actual lookup of variables is done through this single, sorted array.
*/
-static enum config_type
-find_option(const char *name, struct config_generic ** record)
-{
- int i;
+static struct config_generic **guc_variables;
+static int num_guc_variables;
- Assert(name);
+static bool guc_dirty; /* TRUE if need to do commit/abort work */
- for (i = 0; ConfigureNamesBool[i].name; i++)
- if (strcasecmp(ConfigureNamesBool[i].name, name) == 0)
- {
- if (record)
- *record = (struct config_generic *) & ConfigureNamesBool[i];
- return PGC_BOOL;
- }
+static char *guc_string_workspace; /* for avoiding memory leaks */
- for (i = 0; ConfigureNamesInt[i].name; i++)
- if (strcasecmp(ConfigureNamesInt[i].name, name) == 0)
- {
- if (record)
- *record = (struct config_generic *) & ConfigureNamesInt[i];
- return PGC_INT;
- }
-
- for (i = 0; ConfigureNamesReal[i].name; i++)
- if (strcasecmp(ConfigureNamesReal[i].name, name) == 0)
- {
- if (record)
- *record = (struct config_generic *) & ConfigureNamesReal[i];
- return PGC_REAL;
- }
-
- for (i = 0; ConfigureNamesString[i].name; i++)
- if (strcasecmp(ConfigureNamesString[i].name, name) == 0)
- {
- if (record)
- *record = (struct config_generic *) & ConfigureNamesString[i];
- return PGC_STRING;
- }
-
- return PGC_NONE;
-}
+static int guc_var_compare(const void *a, const void *b);
+static void _ShowOption(struct config_generic *record);
/*
- * Reset all options to their specified default values. Must be called
- * with isStartup = true at program startup. May be called later with
- * isStartup = false to reset all resettable options.
+ * Build the sorted array. This is split out so that it could be
+ * re-executed after startup (eg, we could allow loadable modules to
+ * add vars, and then we'd need to re-sort).
*/
-void
-ResetAllOptions(bool isStartup)
+static void
+build_guc_variables(void)
{
+ int num_vars = 0;
+ struct config_generic **guc_vars;
int i;
- for (i = 0; ConfigureNamesBool[i].name; i++)
+ for (i = 0; ConfigureNamesBool[i].gen.name; i++)
{
struct config_bool *conf = &ConfigureNamesBool[i];
- if (isStartup ||
- conf->context == PGC_SUSET || conf->context == PGC_USERSET)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
- }
+ /* Rather than requiring vartype to be filled in by hand, do this: */
+ conf->gen.vartype = PGC_BOOL;
+ num_vars++;
}
- for (i = 0; ConfigureNamesInt[i].name; i++)
+ for (i = 0; ConfigureNamesInt[i].gen.name; i++)
{
struct config_int *conf = &ConfigureNamesInt[i];
- if (isStartup ||
- conf->context == PGC_SUSET || conf->context == PGC_USERSET)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
- }
+ conf->gen.vartype = PGC_INT;
+ num_vars++;
}
- for (i = 0; ConfigureNamesReal[i].name; i++)
+ for (i = 0; ConfigureNamesReal[i].gen.name; i++)
{
struct config_real *conf = &ConfigureNamesReal[i];
- if (isStartup ||
- conf->context == PGC_SUSET || conf->context == PGC_USERSET)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
- }
+ conf->gen.vartype = PGC_REAL;
+ num_vars++;
}
- for (i = 0; ConfigureNamesString[i].name; i++)
+ for (i = 0; ConfigureNamesString[i].gen.name; i++)
{
struct config_string *conf = &ConfigureNamesString[i];
- if (isStartup ||
- conf->context == PGC_SUSET || conf->context == PGC_USERSET)
- {
- char *str = NULL;
+ conf->gen.vartype = PGC_STRING;
+ num_vars++;
+ }
- if (conf->default_val == NULL &&
- conf->boot_default_val)
+ guc_vars = (struct config_generic **)
+ malloc(num_vars * sizeof(struct config_generic *));
+ if (!guc_vars)
+ elog(PANIC, "out of memory");
+
+ num_vars = 0;
+
+ for (i = 0; ConfigureNamesBool[i].gen.name; i++)
+ guc_vars[num_vars++] = & ConfigureNamesBool[i].gen;
+
+ for (i = 0; ConfigureNamesInt[i].gen.name; i++)
+ guc_vars[num_vars++] = & ConfigureNamesInt[i].gen;
+
+ for (i = 0; ConfigureNamesReal[i].gen.name; i++)
+ guc_vars[num_vars++] = & ConfigureNamesReal[i].gen;
+
+ for (i = 0; ConfigureNamesString[i].gen.name; i++)
+ guc_vars[num_vars++] = & ConfigureNamesString[i].gen;
+
+ qsort((void *) guc_vars, num_vars, sizeof(struct config_generic *),
+ guc_var_compare);
+
+ if (guc_variables)
+ free(guc_variables);
+ guc_variables = guc_vars;
+ num_guc_variables = num_vars;
+}
+
+
+/*
+ * Look up option NAME. If it exists, return a pointer to its record,
+ * else return NULL.
+ */
+static struct config_generic *
+find_option(const char *name)
+{
+ const char **key = &name;
+ struct config_generic **res;
+
+ Assert(name);
+
+ /*
+ * by equating const char ** with struct config_generic *, we are
+ * assuming the name field is first in config_generic.
+ */
+ res = (struct config_generic**) bsearch((void *) &key,
+ (void *) guc_variables,
+ num_guc_variables,
+ sizeof(struct config_generic *),
+ guc_var_compare);
+ if (res)
+ return *res;
+ return NULL;
+}
+
+
+/*
+ * comparator for qsorting and bsearching guc_variables array
+ */
+static int
+guc_var_compare(const void *a, const void *b)
+{
+ struct config_generic *confa = *(struct config_generic **) a;
+ struct config_generic *confb = *(struct config_generic **) b;
+ char namea[NAMEDATALEN];
+ char nameb[NAMEDATALEN];
+ int len,
+ i;
+
+ /*
+ * The temptation to use strcasecmp() here must be resisted, because
+ * the array ordering has to remain stable across setlocale() calls.
+ * So, apply an ASCII-only downcasing to both names and use strcmp().
+ */
+ len = strlen(confa->name);
+ if (len >= NAMEDATALEN)
+ len = NAMEDATALEN-1;
+ for (i = 0; i < len; i++)
+ {
+ char ch = confa->name[i];
+
+ if (ch >= 'A' && ch <= 'Z')
+ ch += 'a' - 'A';
+ namea[i] = ch;
+ }
+ namea[len] = '\0';
+
+ len = strlen(confb->name);
+ if (len >= NAMEDATALEN)
+ len = NAMEDATALEN-1;
+ for (i = 0; i < len; i++)
+ {
+ char ch = confb->name[i];
+
+ if (ch >= 'A' && ch <= 'Z')
+ ch += 'a' - 'A';
+ nameb[i] = ch;
+ }
+ nameb[len] = '\0';
+
+ return strcmp(namea, nameb);
+}
+
+
+/*
+ * Initialize GUC options during program startup.
+ */
+void
+InitializeGUCOptions(void)
+{
+ int i;
+ char *env;
+
+ /*
+ * Build sorted array of all GUC variables.
+ */
+ build_guc_variables();
+
+ /*
+ * Load all variables with their compiled-in defaults, and initialize
+ * status fields as needed.
+ *
+ * Note: any errors here are reported with plain ol' printf, since we
+ * shouldn't assume that elog will work before we've initialized its
+ * config variables. An error here would be unexpected anyway...
+ */
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ struct config_generic *gconf = guc_variables[i];
+
+ gconf->status = 0;
+ gconf->reset_source = PGC_S_DEFAULT;
+ gconf->session_source = PGC_S_DEFAULT;
+ gconf->tentative_source = PGC_S_DEFAULT;
+ gconf->source = PGC_S_DEFAULT;
+
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
{
- str = strdup(conf->boot_default_val);
+ struct config_bool *conf = (struct config_bool *) gconf;
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, false))
+ fprintf(stderr, "Failed to initialize %s",
+ conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->session_val = conf->reset_val;
+ break;
+ }
+ case PGC_INT:
+ {
+ struct config_int *conf = (struct config_int *) gconf;
+
+ Assert(conf->reset_val >= conf->min);
+ Assert(conf->reset_val <= conf->max);
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, false))
+ fprintf(stderr, "Failed to initialize %s",
+ conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->session_val = conf->reset_val;
+ break;
+ }
+ case PGC_REAL:
+ {
+ struct config_real *conf = (struct config_real *) gconf;
+
+ Assert(conf->reset_val >= conf->min);
+ Assert(conf->reset_val <= conf->max);
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, false))
+ fprintf(stderr, "Failed to initialize %s",
+ conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->session_val = conf->reset_val;
+ break;
+ }
+ case PGC_STRING:
+ {
+ struct config_string *conf = (struct config_string *) gconf;
+ char *str;
+
+ *conf->variable = NULL;
+ conf->reset_val = NULL;
+ conf->session_val = NULL;
+ conf->tentative_val = NULL;
+
+ if (conf->boot_val == NULL)
+ {
+ /* Cannot set value yet */
+ break;
+ }
+
+ str = strdup(conf->boot_val);
+ if (str == NULL)
+ elog(PANIC, "out of memory");
+ conf->reset_val = str;
+
+ if (conf->assign_hook)
+ {
+ const char *newstr;
+
+ newstr = (*conf->assign_hook) (str, true, false);
+ if (newstr == NULL)
+ {
+ fprintf(stderr, "Failed to initialize %s",
+ conf->gen.name);
+ }
+ else if (newstr != str)
+ {
+ free(str);
+ /* See notes in set_config_option about casting */
+ str = (char *) newstr;
+ conf->reset_val = str;
+ }
+ }
+ *conf->variable = str;
+ conf->session_val = str;
+ break;
+ }
+ }
+ }
+
+ guc_dirty = false;
+
+ guc_string_workspace = NULL;
+
+ /*
+ * Prevent any attempt to override TRANSACTION ISOLATION LEVEL from
+ * non-interactive sources.
+ */
+ SetConfigOption("TRANSACTION ISOLATION LEVEL", "default",
+ PGC_POSTMASTER, PGC_S_OVERRIDE);
+
+ /*
+ * For historical reasons, some GUC parameters can receive defaults
+ * from environment variables. Process those settings.
+ */
+
+ env = getenv("PGPORT");
+ if (env != NULL)
+ SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
+
+ env = getenv("PGDATESTYLE");
+ if (env != NULL)
+ SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
+
+ env = getenv("TZ");
+ if (env != NULL)
+ SetConfigOption("timezone", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
+
+#ifdef MULTIBYTE
+ env = getenv("PGCLIENTENCODING");
+ if (env != NULL)
+ SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
+#endif
+}
+
+
+/*
+ * Reset all options to their saved default values (implements RESET ALL)
+ */
+void
+ResetAllOptions(void)
+{
+ int i;
+
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ struct config_generic *gconf = guc_variables[i];
+
+ /* Don't reset non-SET-able values */
+ if (gconf->context != PGC_SUSET && gconf->context != PGC_USERSET)
+ continue;
+ /* Don't reset if special exclusion from RESET ALL */
+ if (gconf->flags & GUC_NO_RESET_ALL)
+ continue;
+ /* No need to reset if wasn't SET */
+ if (gconf->source <= PGC_S_OVERRIDE)
+ continue;
+
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
+ {
+ struct config_bool *conf = (struct config_bool *) gconf;
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, true))
+ elog(ERROR, "Failed to reset %s", conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->tentative_val = conf->reset_val;
+ conf->gen.source = conf->gen.reset_source;
+ conf->gen.tentative_source = conf->gen.reset_source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ break;
+ }
+ case PGC_INT:
+ {
+ struct config_int *conf = (struct config_int *) gconf;
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, true))
+ elog(ERROR, "Failed to reset %s", conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->tentative_val = conf->reset_val;
+ conf->gen.source = conf->gen.reset_source;
+ conf->gen.tentative_source = conf->gen.reset_source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ break;
+ }
+ case PGC_REAL:
+ {
+ struct config_real *conf = (struct config_real *) gconf;
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->reset_val, true, true))
+ elog(ERROR, "Failed to reset %s", conf->gen.name);
+ *conf->variable = conf->reset_val;
+ conf->tentative_val = conf->reset_val;
+ conf->gen.source = conf->gen.reset_source;
+ conf->gen.tentative_source = conf->gen.reset_source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ break;
+ }
+ case PGC_STRING:
+ {
+ struct config_string *conf = (struct config_string *) gconf;
+ char *str;
+
+ if (conf->reset_val == NULL)
+ {
+ /* Nothing to reset to, as yet; so do nothing */
+ break;
+ }
+
+ str = strdup(conf->reset_val);
if (str == NULL)
elog(ERROR, "out of memory");
- conf->default_val = str;
+
+ /*
+ * Remember string in workspace, so that we can free it
+ * and avoid a permanent memory leak if hook elogs.
+ */
+ if (guc_string_workspace)
+ free(guc_string_workspace);
+ guc_string_workspace = str;
+
+ if (conf->assign_hook)
+ {
+ const char *newstr;
+
+ newstr = (*conf->assign_hook) (str, true, true);
+ if (newstr == NULL)
+ elog(ERROR, "Failed to reset %s", conf->gen.name);
+ else if (newstr != str)
+ {
+ free(str);
+ /* See notes in set_config_option about casting */
+ str = (char *) newstr;
+ }
+ }
+
+ guc_string_workspace = NULL;
+
+ SET_STRING_VARIABLE(conf, str);
+ SET_STRING_TENTATIVE_VAL(conf, str);
+ conf->gen.source = conf->gen.reset_source;
+ conf->gen.tentative_source = conf->gen.reset_source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ break;
}
- if (conf->default_val)
- {
- str = strdup(conf->default_val);
- if (str == NULL)
- elog(ERROR, "out of memory");
- }
- if (conf->assign_hook)
- (conf->assign_hook) (str);
- if (*conf->variable)
- free(*conf->variable);
- *conf->variable = str;
}
}
}
+/*
+ * Do GUC processing at transaction commit or abort.
+ */
+void
+AtEOXact_GUC(bool isCommit)
+{
+ int i;
+
+ /* Quick exit if nothing's changed in this transaction */
+ if (!guc_dirty)
+ return;
+
+ /* Prevent memory leak if elog during an assign_hook */
+ if (guc_string_workspace)
+ {
+ free(guc_string_workspace);
+ guc_string_workspace = NULL;
+ }
+
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ struct config_generic *gconf = guc_variables[i];
+
+ /* Skip if nothing's happened to this var in this transaction */
+ if (gconf->status == 0)
+ continue;
+
+ switch (gconf->vartype)
+ {
+ case PGC_BOOL:
+ {
+ struct config_bool *conf = (struct config_bool *) gconf;
+
+ if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
+ {
+ conf->session_val = conf->tentative_val;
+ conf->gen.session_source = conf->gen.tentative_source;
+ }
+
+ if (*conf->variable != conf->session_val)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->session_val,
+ true, false))
+ elog(LOG, "Failed to commit %s", conf->gen.name);
+ *conf->variable = conf->session_val;
+ }
+ conf->gen.source = conf->gen.session_source;
+ conf->gen.status = 0;
+ break;
+ }
+ case PGC_INT:
+ {
+ struct config_int *conf = (struct config_int *) gconf;
+
+ if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
+ {
+ conf->session_val = conf->tentative_val;
+ conf->gen.session_source = conf->gen.tentative_source;
+ }
+
+ if (*conf->variable != conf->session_val)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->session_val,
+ true, false))
+ elog(LOG, "Failed to commit %s", conf->gen.name);
+ *conf->variable = conf->session_val;
+ }
+ conf->gen.source = conf->gen.session_source;
+ conf->gen.status = 0;
+ break;
+ }
+ case PGC_REAL:
+ {
+ struct config_real *conf = (struct config_real *) gconf;
+
+ if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
+ {
+ conf->session_val = conf->tentative_val;
+ conf->gen.session_source = conf->gen.tentative_source;
+ }
+
+ if (*conf->variable != conf->session_val)
+ {
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (conf->session_val,
+ true, false))
+ elog(LOG, "Failed to commit %s", conf->gen.name);
+ *conf->variable = conf->session_val;
+ }
+ conf->gen.source = conf->gen.session_source;
+ conf->gen.status = 0;
+ break;
+ }
+ case PGC_STRING:
+ {
+ struct config_string *conf = (struct config_string *) gconf;
+
+ if (isCommit && (conf->gen.status & GUC_HAVE_TENTATIVE))
+ {
+ SET_STRING_SESSION_VAL(conf, conf->tentative_val);
+ conf->gen.session_source = conf->gen.tentative_source;
+ conf->tentative_val = NULL; /* transfer ownership */
+ }
+ else
+ {
+ SET_STRING_TENTATIVE_VAL(conf, NULL);
+ }
+
+ if (*conf->variable != conf->session_val)
+ {
+ char *str = conf->session_val;
+
+ if (conf->assign_hook)
+ {
+ const char *newstr;
+
+ newstr = (*conf->assign_hook) (str, true, false);
+ if (newstr == NULL)
+ elog(LOG, "Failed to commit %s", conf->gen.name);
+ else if (newstr != str)
+ {
+ /* See notes in set_config_option about casting */
+ str = (char *) newstr;
+ SET_STRING_SESSION_VAL(conf, str);
+ }
+ }
+
+ SET_STRING_VARIABLE(conf, str);
+ }
+ conf->gen.source = conf->gen.session_source;
+ conf->gen.status = 0;
+ break;
+ }
+ }
+ }
+
+ guc_dirty = false;
+}
+
/*
* Try to interpret value as boolean value. Valid values are: true,
@@ -900,7 +1511,7 @@ parse_real(const char *value, double *result)
/*
* Sets option `name' to given value. The value should be a string
* which is going to be parsed and converted to the appropriate data
- * type. Parameter context should indicate in which context this
+ * type. The context and source parameters indicate in which context this
* function is being called so it can apply the access restrictions
* properly.
*
@@ -909,49 +1520,45 @@ parse_real(const char *value, double *result)
* the checks to see if it would work.
*
* If there is an error (non-existing option, invalid value) then an
- * elog(ERROR) is thrown *unless* this is called as part of the
- * configuration file re-read in the SIGHUP handler, in which case we
- * simply write the error message via elog(DEBUG) and return false. In
- * all other cases the function returns true. This is working around
- * the deficiencies in the elog mechanism, so don't blame me.
+ * elog(ERROR) is thrown *unless* this is called in a context where we
+ * don't want to elog (currently, startup or SIGHUP config file reread).
+ * In that case we write a suitable error message via elog(DEBUG) and
+ * return false. This is working around the deficiencies in the elog
+ * mechanism, so don't blame me. In all other cases, the function
+ * returns true, including cases where the input is valid but we chose
+ * not to apply it because of context or source-priority considerations.
*
* See also SetConfigOption for an external interface.
*/
bool
set_config_option(const char *name, const char *value,
- GucContext context, bool DoIt, GucSource source)
+ GucContext context, GucSource source,
+ bool isLocal, bool DoIt)
{
struct config_generic *record;
- enum config_type type;
int elevel;
+ bool interactive;
bool makeDefault;
if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
elevel = DEBUG1;
- else if (guc_session_init)
+ else if (source == PGC_S_DATABASE || source == PGC_S_USER)
elevel = INFO;
else
elevel = ERROR;
- type = find_option(name, &record);
- if (type == PGC_NONE)
+ record = find_option(name);
+ if (record == NULL)
{
elog(elevel, "'%s' is not a valid option name", name);
return false;
}
- if (record->source > source)
- {
- elog(DEBUG2, "setting %s refused because previous source is higher",
- name);
- return false;
- }
- makeDefault = source < PGC_S_SESSION;
-
/*
* Check if the option can be set at this time. See guc.h for the
* precise rules. Note that we don't want to throw errors if we're in
- * the SIGHUP context. In that case we just ignore the attempt.
+ * the SIGHUP context. In that case we just ignore the attempt and
+ * return true.
*/
switch (record->context)
{
@@ -959,11 +1566,18 @@ set_config_option(const char *name, const char *value,
if (context == PGC_SIGHUP)
return true;
if (context != PGC_POSTMASTER)
- elog(ERROR, "'%s' cannot be changed after server start", name);
+ {
+ elog(elevel, "'%s' cannot be changed after server start",
+ name);
+ return false;
+ }
break;
case PGC_SIGHUP:
if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
- elog(ERROR, "'%s' cannot be changed now", name);
+ {
+ elog(elevel, "'%s' cannot be changed now", name);
+ return false;
+ }
/*
* Hmm, the idea of the SIGHUP context is "ought to be global,
@@ -987,51 +1601,110 @@ set_config_option(const char *name, const char *value,
return true;
}
else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
- elog(ERROR, "'%s' cannot be set after connection start", name);
+ {
+ elog(elevel, "'%s' cannot be set after connection start",
+ name);
+ return false;
+ }
break;
case PGC_SUSET:
if (context == PGC_USERSET || context == PGC_BACKEND)
- elog(ERROR, "permission denied");
+ {
+ elog(elevel, "'%s': permission denied", name);
+ return false;
+ }
break;
case PGC_USERSET:
/* always okay */
break;
}
+ interactive = (source >= PGC_S_SESSION);
+ makeDefault = (source <= PGC_S_OVERRIDE) && (value != NULL);
+
+ /*
+ * Ignore attempted set if overridden by previously processed setting.
+ * However, if DoIt is false then plow ahead anyway since we are trying
+ * to find out if the value is potentially good, not actually use it.
+ * Also keep going if makeDefault is true, since we may want to set
+ * the reset/session values even if we can't set the variable itself.
+ */
+ if (record->source > source)
+ {
+ if (DoIt && !makeDefault)
+ {
+ elog(DEBUG2, "setting %s ignored because previous source is higher",
+ name);
+ return true;
+ }
+ DoIt = false; /* we won't change the variable itself */
+ }
+
/*
* Evaluate value and set variable
*/
- switch (type)
+ switch (record->vartype)
{
case PGC_BOOL:
{
struct config_bool *conf = (struct config_bool *) record;
+ bool newval;
if (value)
{
- bool boolval;
-
- if (!parse_bool(value, &boolval))
+ if (!parse_bool(value, &newval))
{
- elog(elevel, "option '%s' requires a boolean value", name);
+ elog(elevel, "option '%s' requires a boolean value",
+ name);
return false;
}
- /* no parse_hook needed for booleans */
+ }
+ else
+ {
+ newval = conf->reset_val;
+ source = conf->gen.reset_source;
+ }
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval, DoIt, interactive))
+ {
+ elog(elevel, "invalid value for option '%s': %d",
+ name, (int) newval);
+ return false;
+ }
+
+ if (DoIt || makeDefault)
+ {
if (DoIt)
{
- if (conf->assign_hook)
- (conf->assign_hook) (boolval);
- *conf->variable = boolval;
- if (makeDefault)
- conf->default_val = boolval;
- conf->source = source;
+ *conf->variable = newval;
+ conf->gen.source = source;
+ }
+ if (makeDefault)
+ {
+ if (conf->gen.reset_source <= source)
+ {
+ conf->reset_val = newval;
+ conf->gen.reset_source = source;
+ }
+ if (conf->gen.session_source <= source)
+ {
+ conf->session_val = newval;
+ conf->gen.session_source = source;
+ }
+ }
+ else if (isLocal)
+ {
+ conf->gen.status |= GUC_HAVE_LOCAL;
+ guc_dirty = true;
+ }
+ else
+ {
+ conf->tentative_val = newval;
+ conf->gen.tentative_source = source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
}
- }
- else if (DoIt)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
}
break;
}
@@ -1039,44 +1712,70 @@ set_config_option(const char *name, const char *value,
case PGC_INT:
{
struct config_int *conf = (struct config_int *) record;
+ int newval;
if (value)
{
- int intval;
-
- if (!parse_int(value, &intval))
+ if (!parse_int(value, &newval))
{
- elog(elevel, "option '%s' expects an integer value", name);
+ elog(elevel, "option '%s' expects an integer value",
+ name);
return false;
}
- if (intval < conf->min || intval > conf->max)
+ if (newval < conf->min || newval > conf->max)
{
elog(elevel, "option '%s' value %d is outside"
" of permissible range [%d .. %d]",
- name, intval, conf->min, conf->max);
+ name, newval, conf->min, conf->max);
return false;
}
- if (conf->parse_hook && !(conf->parse_hook) (intval))
- {
- elog(elevel, "invalid value for option '%s': %d",
- name, intval);
- return false;
- }
- if (DoIt)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (intval);
- *conf->variable = intval;
- if (makeDefault)
- conf->default_val = intval;
- conf->source = source;
- }
}
- else if (DoIt)
+ else
{
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
+ newval = conf->reset_val;
+ source = conf->gen.reset_source;
+ }
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval, DoIt, interactive))
+ {
+ elog(elevel, "invalid value for option '%s': %d",
+ name, newval);
+ return false;
+ }
+
+ if (DoIt || makeDefault)
+ {
+ if (DoIt)
+ {
+ *conf->variable = newval;
+ conf->gen.source = source;
+ }
+ if (makeDefault)
+ {
+ if (conf->gen.reset_source <= source)
+ {
+ conf->reset_val = newval;
+ conf->gen.reset_source = source;
+ }
+ if (conf->gen.session_source <= source)
+ {
+ conf->session_val = newval;
+ conf->gen.session_source = source;
+ }
+ }
+ else if (isLocal)
+ {
+ conf->gen.status |= GUC_HAVE_LOCAL;
+ guc_dirty = true;
+ }
+ else
+ {
+ conf->tentative_val = newval;
+ conf->gen.tentative_source = source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ }
}
break;
}
@@ -1084,44 +1783,70 @@ set_config_option(const char *name, const char *value,
case PGC_REAL:
{
struct config_real *conf = (struct config_real *) record;
+ double newval;
if (value)
{
- double dval;
-
- if (!parse_real(value, &dval))
+ if (!parse_real(value, &newval))
{
- elog(elevel, "option '%s' expects a real number", name);
+ elog(elevel, "option '%s' expects a real number",
+ name);
return false;
}
- if (dval < conf->min || dval > conf->max)
+ if (newval < conf->min || newval > conf->max)
{
elog(elevel, "option '%s' value %g is outside"
" of permissible range [%g .. %g]",
- name, dval, conf->min, conf->max);
+ name, newval, conf->min, conf->max);
return false;
}
- if (conf->parse_hook && !(conf->parse_hook) (dval))
- {
- elog(elevel, "invalid value for option '%s': %g",
- name, dval);
- return false;
- }
- if (DoIt)
- {
- if (conf->assign_hook)
- (conf->assign_hook) (dval);
- *conf->variable = dval;
- if (makeDefault)
- conf->default_val = dval;
- conf->source = source;
- }
}
- else if (DoIt)
+ else
{
- if (conf->assign_hook)
- (conf->assign_hook) (conf->default_val);
- *conf->variable = conf->default_val;
+ newval = conf->reset_val;
+ source = conf->gen.reset_source;
+ }
+
+ if (conf->assign_hook)
+ if (!(*conf->assign_hook) (newval, DoIt, interactive))
+ {
+ elog(elevel, "invalid value for option '%s': %g",
+ name, newval);
+ return false;
+ }
+
+ if (DoIt || makeDefault)
+ {
+ if (DoIt)
+ {
+ *conf->variable = newval;
+ conf->gen.source = source;
+ }
+ if (makeDefault)
+ {
+ if (conf->gen.reset_source <= source)
+ {
+ conf->reset_val = newval;
+ conf->gen.reset_source = source;
+ }
+ if (conf->gen.session_source <= source)
+ {
+ conf->session_val = newval;
+ conf->gen.session_source = source;
+ }
+ }
+ else if (isLocal)
+ {
+ conf->gen.status |= GUC_HAVE_LOCAL;
+ guc_dirty = true;
+ }
+ else
+ {
+ conf->tentative_val = newval;
+ conf->gen.tentative_source = source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ }
}
break;
}
@@ -1129,76 +1854,118 @@ set_config_option(const char *name, const char *value,
case PGC_STRING:
{
struct config_string *conf = (struct config_string *) record;
+ char *newval;
if (value)
{
- if (conf->parse_hook && !(conf->parse_hook) (value))
- {
- elog(elevel, "invalid value for option '%s': '%s'",
- name, value);
- return false;
- }
- if (DoIt)
- {
- char *str;
-
- str = strdup(value);
- if (str == NULL)
- {
- elog(elevel, "out of memory");
- return false;
- }
- if (conf->assign_hook)
- (conf->assign_hook) (str);
- if (*conf->variable)
- free(*conf->variable);
- *conf->variable = str;
- if (makeDefault)
- {
- str = strdup(value);
- if (str == NULL)
- {
- elog(elevel, "out of memory");
- return false;
- }
- if (conf->default_val)
- free(conf->default_val);
- conf->default_val = str;
- }
- conf->source = source;
- }
- }
- else if (DoIt)
- {
- char *str;
-
- if (!conf->default_val && conf->boot_default_val)
- {
- str = strdup(conf->boot_default_val);
- if (str == NULL)
- {
- elog(elevel, "out of memory");
- return false;
- }
- conf->default_val = str;
- }
- str = strdup(conf->default_val);
- if (str == NULL)
+ newval = strdup(value);
+ if (newval == NULL)
{
elog(elevel, "out of memory");
return false;
}
- if (conf->assign_hook)
- (conf->assign_hook) (str);
- if (*conf->variable)
- free(*conf->variable);
- *conf->variable = str;
+ }
+ else if (conf->reset_val)
+ {
+ newval = strdup(conf->reset_val);
+ if (newval == NULL)
+ {
+ elog(elevel, "out of memory");
+ return false;
+ }
+ source = conf->gen.reset_source;
+ }
+ else
+ {
+ /* Nothing to reset to, as yet; so do nothing */
+ break;
+ }
+
+ /*
+ * Remember string in workspace, so that we can free it
+ * and avoid a permanent memory leak if hook elogs.
+ */
+ if (guc_string_workspace)
+ free(guc_string_workspace);
+ guc_string_workspace = newval;
+
+ if (conf->assign_hook)
+ {
+ const char *hookresult;
+
+ hookresult = (*conf->assign_hook) (newval,
+ DoIt, interactive);
+ guc_string_workspace = NULL;
+ if (hookresult == NULL)
+ {
+ free(newval);
+ elog(elevel, "invalid value for option '%s': '%s'",
+ name, value ? value : "");
+ return false;
+ }
+ else if (hookresult != newval)
+ {
+ free(newval);
+ /*
+ * Having to cast away const here is annoying, but the
+ * alternative is to declare assign_hooks as returning
+ * char*, which would mean they'd have to cast away
+ * const, or as both taking and returning char*, which
+ * doesn't seem attractive either --- we don't want
+ * them to scribble on the passed str.
+ */
+ newval = (char *) hookresult;
+ }
+ }
+
+ guc_string_workspace = NULL;
+
+ if (DoIt || makeDefault)
+ {
+ if (DoIt)
+ {
+ SET_STRING_VARIABLE(conf, newval);
+ conf->gen.source = source;
+ }
+ if (makeDefault)
+ {
+ if (conf->gen.reset_source <= source)
+ {
+ SET_STRING_RESET_VAL(conf, newval);
+ conf->gen.reset_source = source;
+ }
+ if (conf->gen.session_source <= source)
+ {
+ SET_STRING_SESSION_VAL(conf, newval);
+ conf->gen.session_source = source;
+ }
+ /* Perhaps we didn't install newval anywhere */
+ if (newval != *conf->variable &&
+ newval != conf->session_val &&
+ newval != conf->reset_val)
+ free(newval);
+ }
+ else if (isLocal)
+ {
+ conf->gen.status |= GUC_HAVE_LOCAL;
+ guc_dirty = true;
+ }
+ else
+ {
+ SET_STRING_TENTATIVE_VAL(conf, newval);
+ conf->gen.tentative_source = source;
+ conf->gen.status |= GUC_HAVE_TENTATIVE;
+ guc_dirty = true;
+ }
+ }
+ else
+ {
+ free(newval);
}
break;
}
-
- default:;
}
+
return true;
}
@@ -1206,21 +1973,21 @@ set_config_option(const char *name, const char *value,
/*
* Set a config option to the given value. See also set_config_option,
- * this is just the wrapper to be called from the outside.
+ * this is just the wrapper to be called from outside GUC. NB: this
+ * is used only for non-transactional operations.
*/
void
SetConfigOption(const char *name, const char *value,
GucContext context, GucSource source)
{
- (void) set_config_option(name, value, context, true, source);
+ (void) set_config_option(name, value, context, source, false, true);
}
/*
- * This is more or less the SHOW command. It returns a string with the
- * value of the option `name'. If the option doesn't exist, throw an
- * elog and don't return.
+ * Fetch the current value of the option `name'. If the option doesn't exist,
+ * throw an elog and don't return.
*
* The string is *not* allocated for modification and is really only
* valid until the next call to configuration related functions.
@@ -1230,13 +1997,12 @@ GetConfigOption(const char *name)
{
struct config_generic *record;
static char buffer[256];
- enum config_type opttype;
- opttype = find_option(name, &record);
- if (opttype == PGC_NONE)
+ record = find_option(name);
+ if (record == NULL)
elog(ERROR, "Option '%s' is not recognized", name);
- switch (opttype)
+ switch (record->vartype)
{
case PGC_BOOL:
return *((struct config_bool *) record)->variable ? "on" : "off";
@@ -1253,68 +2019,298 @@ GetConfigOption(const char *name)
case PGC_STRING:
return *((struct config_string *) record)->variable;
-
- default:
- ;
}
return NULL;
}
-static void
-_ShowOption(enum config_type opttype, struct config_generic * record)
+/*
+ * Get the RESET value associated with the given option.
+ */
+const char *
+GetConfigOptionResetString(const char *name)
{
- char buffer[256];
- char *val;
+ struct config_generic *record;
+ static char buffer[256];
- switch (opttype)
+ record = find_option(name);
+ if (record == NULL)
+ elog(ERROR, "Option '%s' is not recognized", name);
+
+ switch (record->vartype)
{
case PGC_BOOL:
- val = *((struct config_bool *) record)->variable ? "on" : "off";
- break;
+ return ((struct config_bool *) record)->reset_val ? "on" : "off";
case PGC_INT:
snprintf(buffer, sizeof(buffer), "%d",
- *((struct config_int *) record)->variable);
- val = buffer;
- break;
+ ((struct config_int *) record)->reset_val);
+ return buffer;
case PGC_REAL:
snprintf(buffer, sizeof(buffer), "%g",
- *((struct config_real *) record)->variable);
- val = buffer;
- break;
+ ((struct config_real *) record)->reset_val);
+ return buffer;
case PGC_STRING:
- val = strlen(*((struct config_string *) record)->variable) != 0 ?
- *((struct config_string *) record)->variable : "unset";
- break;
-
- default:
- val = "???";
+ return ((struct config_string *) record)->reset_val;
}
- elog(INFO, "%s is %s", record->name, val);
+ return NULL;
}
+
+
+/*
+ * flatten_set_variable_args
+ * Given a parsenode List as emitted by the grammar for SET,
+ * convert to the flat string representation used by GUC.
+ *
+ * We need to be told the name of the variable the args are for, because
+ * the flattening rules vary (ugh).
+ *
+ * The result is NULL if input is NIL (ie, SET ... TO DEFAULT), otherwise
+ * a palloc'd string.
+ */
+char *
+flatten_set_variable_args(const char *name, List *args)
+{
+ struct config_generic *record;
+ int flags;
+ StringInfoData buf;
+ List *l;
+
+ /* Fast path if just DEFAULT */
+ if (args == NIL)
+ return NULL;
+
+ record = find_option(name);
+ if (record == NULL)
+ flags = 0; /* default assumptions */
+ else
+ flags = record->flags;
+
+ /* Complain if list input and non-list variable */
+ if ((flags & GUC_LIST_INPUT) == 0 &&
+ lnext(args) != NIL)
+ elog(ERROR, "SET %s takes only one argument", name);
+
+ initStringInfo(&buf);
+
+ foreach(l, args)
+ {
+ A_Const *arg = (A_Const *) lfirst(l);
+ char *val;
+
+ if (l != args)
+ appendStringInfo(&buf, ", ");
+
+ if (!IsA(arg, A_Const))
+ elog(ERROR, "flatten_set_variable_args: unexpected input");
+
+ switch (nodeTag(&arg->val))
+ {
+ case T_Integer:
+ appendStringInfo(&buf, "%ld", intVal(&arg->val));
+ break;
+ case T_Float:
+ /* represented as a string, so just copy it */
+ appendStringInfo(&buf, "%s", strVal(&arg->val));
+ break;
+ case T_String:
+ val = strVal(&arg->val);
+ if (arg->typename != NULL)
+ {
+ /*
+ * Must be a ConstInterval argument for TIME ZONE.
+ * Coerce to interval and back to normalize the value
+ * and account for any typmod.
+ */
+ Datum interval;
+ char *intervalout;
+
+ interval =
+ DirectFunctionCall3(interval_in,
+ CStringGetDatum(val),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(arg->typename->typmod));
+
+ intervalout =
+ DatumGetCString(DirectFunctionCall3(interval_out,
+ interval,
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1)));
+ appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
+ }
+ else
+ {
+ /*
+ * Plain string literal or identifier. For quote mode,
+ * quote it if it's not a vanilla identifier.
+ */
+ if (flags & GUC_LIST_QUOTE)
+ appendStringInfo(&buf, "%s", quote_identifier(val));
+ else
+ appendStringInfo(&buf, "%s", val);
+ }
+ break;
+ default:
+ elog(ERROR, "flatten_set_variable_args: unexpected input");
+ break;
+ }
+ }
+
+ return buf.data;
+}
+
+
+/*
+ * SET command
+ */
+void
+SetPGVariable(const char *name, List *args, bool is_local)
+{
+ char *argstring = flatten_set_variable_args(name, args);
+
+ /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
+ set_config_option(name,
+ argstring,
+ (superuser() ? PGC_SUSET : PGC_USERSET),
+ PGC_S_SESSION,
+ is_local,
+ true);
+}
+
+/*
+ * SHOW command
+ */
+void
+GetPGVariable(const char *name)
+{
+ if (strcasecmp(name, "all") == 0)
+ ShowAllGUCConfig();
+ else
+ ShowGUCConfigOption(name);
+}
+
+/*
+ * RESET command
+ */
+void
+ResetPGVariable(const char *name)
+{
+ if (strcasecmp(name, "all") == 0)
+ ResetAllOptions();
+ else
+ set_config_option(name,
+ NULL,
+ (superuser() ? PGC_SUSET : PGC_USERSET),
+ PGC_S_SESSION,
+ false,
+ true);
+}
+
+
+/*
+ * SHOW command
+ */
+void
+ShowGUCConfigOption(const char *name)
+{
+ struct config_generic *record;
+
+ record = find_option(name);
+ if (record == NULL)
+ elog(ERROR, "Option '%s' is not recognized", name);
+
+ _ShowOption(record);
+}
+
+/*
+ * SHOW ALL command
+ */
void
ShowAllGUCConfig(void)
{
int i;
- for (i = 0; ConfigureNamesBool[i].name; i++)
- _ShowOption(PGC_BOOL, (struct config_generic *) & ConfigureNamesBool[i]);
+ for (i = 0; i < num_guc_variables; i++)
+ {
+ struct config_generic *conf = guc_variables[i];
- for (i = 0; ConfigureNamesInt[i].name; i++)
- _ShowOption(PGC_INT, (struct config_generic *) & ConfigureNamesInt[i]);
-
- for (i = 0; ConfigureNamesReal[i].name; i++)
- _ShowOption(PGC_REAL, (struct config_generic *) & ConfigureNamesReal[i]);
-
- for (i = 0; ConfigureNamesString[i].name; i++)
- _ShowOption(PGC_STRING, (struct config_generic *) & ConfigureNamesString[i]);
+ if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
+ _ShowOption(conf);
+ }
}
+static void
+_ShowOption(struct config_generic *record)
+{
+ char buffer[256];
+ const char *val;
+ switch (record->vartype)
+ {
+ case PGC_BOOL:
+ {
+ struct config_bool *conf = (struct config_bool *) record;
+ if (conf->show_hook)
+ val = (*conf->show_hook) ();
+ else
+ val = *conf->variable ? "on" : "off";
+ }
+ break;
+
+ case PGC_INT:
+ {
+ struct config_int *conf = (struct config_int *) record;
+
+ if (conf->show_hook)
+ val = (*conf->show_hook) ();
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%d",
+ *conf->variable);
+ val = buffer;
+ }
+ }
+ break;
+
+ case PGC_REAL:
+ {
+ struct config_real *conf = (struct config_real *) record;
+
+ if (conf->show_hook)
+ val = (*conf->show_hook) ();
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%g",
+ *conf->variable);
+ val = buffer;
+ }
+ }
+ break;
+
+ case PGC_STRING:
+ {
+ struct config_string *conf = (struct config_string *) record;
+
+ if (conf->show_hook)
+ val = (*conf->show_hook) ();
+ else if (*conf->variable && **conf->variable)
+ val = *conf->variable;
+ else
+ val = "unset";
+ }
+ break;
+
+ default:
+ /* just to keep compiler quiet */
+ val = "???";
+ break;
+ }
+
+ elog(INFO, "%s is %s", record->name, val);
+}
/*
@@ -1366,59 +2362,54 @@ ParseLongOption(const char *string, char **name, char **value)
#ifdef HAVE_SYSLOG
-static bool
-check_facility(const char *facility)
+static const char *
+assign_facility(const char *facility, bool doit, bool interactive)
{
if (strcasecmp(facility, "LOCAL0") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL1") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL2") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL3") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL4") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL5") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL6") == 0)
- return true;
+ return facility;
if (strcasecmp(facility, "LOCAL7") == 0)
- return true;
- return false;
+ return facility;
+ return NULL;
}
+
#endif
-
-static bool
-check_defaultxactisolevel(const char *value)
+static const char *
+assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
{
- return (strcasecmp(value, "read committed") == 0
- || strcasecmp(value, "serializable") == 0)
- ? true : false;
-}
-
-
-static void
-assign_defaultxactisolevel(const char *value)
-{
- if (strcasecmp(value, "serializable") == 0)
- DefaultXactIsoLevel = XACT_SERIALIZABLE;
- else if (strcasecmp(value, "read committed") == 0)
- DefaultXactIsoLevel = XACT_READ_COMMITTED;
+ if (strcasecmp(newval, "serializable") == 0)
+ { if (doit) DefaultXactIsoLevel = XACT_SERIALIZABLE; }
+ else if (strcasecmp(newval, "read committed") == 0)
+ { if (doit) DefaultXactIsoLevel = XACT_READ_COMMITTED; }
else
- elog(ERROR, "bogus transaction isolation level");
+ return NULL;
+ return newval;
}
-
+/*
+ * Handle options fetched from pg_database.datconfig or pg_shadow.useconfig.
+ */
void
ProcessGUCArray(ArrayType *array, GucSource source)
{
int i;
- Assert(array);
+ Assert(array != NULL);
+ Assert(source == PGC_S_DATABASE || source == PGC_S_USER);
for (i = 1; i <= ARR_DIMS(array)[0]; i++)
{
@@ -1445,12 +2436,12 @@ ProcessGUCArray(ArrayType *array, GucSource source)
continue;
}
- /* prevent errors from incorrect options */
- guc_session_init = true;
-
+ /*
+ * We process all these options at SUSET level. We assume that the
+ * right to insert an option into pg_database or pg_shadow was
+ * checked when it was inserted.
+ */
SetConfigOption(name, value, PGC_SUSET, source);
-
- guc_session_init = false;
}
}
@@ -1469,7 +2460,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
/* test if the option is valid */
set_config_option(name, value,
superuser() ? PGC_SUSET : PGC_USERSET,
- false, PGC_S_INFINITY);
+ PGC_S_SESSION, false, false);
newval = palloc(strlen(name) + 1 + strlen(value) + 1);
sprintf(newval, "%s=%s", name, value);
@@ -1525,7 +2516,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
/* test if the option is valid */
set_config_option(name, NULL,
superuser() ? PGC_SUSET : PGC_USERSET,
- false, PGC_S_INFINITY);
+ PGC_S_SESSION, false, false);
newarray = construct_array(NULL, 0, false, -1, 'i');
index = 1;
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 843ad5ce15..3fae561d7c 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -192,7 +192,10 @@
#
#dynamic_library_path = '$libdir'
#search_path = '$user,public'
+#datestyle = 'iso, us'
+#timezone = unknown # actually, defaults to TZ environment setting
#australian_timezones = false
+#client_encoding = sql_ascii # actually, defaults to database encoding
#authentication_timeout = 60 # min 1, max 600
#deadlock_timeout = 1000
#default_transaction_isolation = 'read committed'
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 9252a8d324..92e74b88d7 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: xlog.h,v 1.29 2002/03/15 19:20:36 tgl Exp $
+ * $Id: xlog.h,v 1.30 2002/05/17 01:19:19 tgl Exp $
*/
#ifndef XLOG_H
#define XLOG_H
@@ -216,7 +216,7 @@ extern XLogRecPtr GetRedoRecPtr(void);
*/
extern XLogRecPtr GetUndoRecPtr(void);
-extern bool check_xlog_sync_method(const char *method);
-extern void assign_xlog_sync_method(const char *method);
+extern const char *assign_xlog_sync_method(const char *method,
+ bool doit, bool interactive);
#endif /* XLOG_H */
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 545b1a1383..8fe62acb0e 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: namespace.h,v 1.12 2002/05/01 23:06:41 tgl Exp $
+ * $Id: namespace.h,v 1.13 2002/05/17 01:19:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -75,8 +75,8 @@ extern bool isTempNamespace(Oid namespaceId);
/* stuff for search_path GUC variable */
extern char *namespace_search_path;
-extern bool check_search_path(const char *proposed);
-extern void assign_search_path(const char *newval);
+extern const char *assign_search_path(const char *newval,
+ bool doit, bool interactive);
extern void InitializeSearchPath(void);
extern List *fetch_search_path(void);
diff --git a/src/include/commands/variable.h b/src/include/commands/variable.h
index f4f12c9712..bdca5c88a9 100644
--- a/src/include/commands/variable.h
+++ b/src/include/commands/variable.h
@@ -1,18 +1,32 @@
/*
- * Headers for handling of 'SET var TO', 'SHOW var' and 'RESET var'
- * statements
+ * variable.h
+ * Routines for handling specialized SET variables.
*
- * $Id: variable.h,v 1.17 2001/11/05 17:46:33 momjian Exp $
+ * $Id: variable.h,v 1.18 2002/05/17 01:19:19 tgl Exp $
*
*/
#ifndef VARIABLE_H
#define VARIABLE_H
-extern void SetPGVariable(const char *name, List *args);
-extern void GetPGVariable(const char *name);
-extern void ResetPGVariable(const char *name);
-
-extern void set_default_datestyle(void);
-extern void set_default_client_encoding(void);
+extern const char *assign_datestyle(const char *value,
+ bool doit, bool interactive);
+extern const char *show_datestyle(void);
+extern const char *assign_timezone(const char *value,
+ bool doit, bool interactive);
+extern const char *show_timezone(void);
+extern const char *assign_XactIsoLevel(const char *value,
+ bool doit, bool interactive);
+extern const char *show_XactIsoLevel(void);
+extern bool assign_random_seed(double value,
+ bool doit, bool interactive);
+extern const char *show_random_seed(void);
+extern const char *assign_client_encoding(const char *value,
+ bool doit, bool interactive);
+extern const char *assign_server_encoding(const char *value,
+ bool doit, bool interactive);
+extern const char *show_server_encoding(void);
+extern const char *assign_session_authorization(const char *value,
+ bool doit, bool interactive);
+extern const char *show_session_authorization(void);
#endif /* VARIABLE_H */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 09e1c0fe63..2e5fc76bb7 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: miscadmin.h,v 1.103 2002/05/05 00:03:29 tgl Exp $
+ * $Id: miscadmin.h,v 1.104 2002/05/17 01:19:19 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to
@@ -211,7 +211,7 @@ extern Oid GetSessionUserId(void);
extern void SetSessionUserId(Oid userid);
extern void InitializeSessionUserId(const char *username);
extern void InitializeSessionUserIdStandalone(void);
-extern void SetSessionAuthorization(const char *username);
+extern void SetSessionAuthorization(Oid userid);
extern void SetDataDir(const char *dir);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 0c5672dd67..a0bf47d7ed 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.176 2002/05/12 20:10:04 tgl Exp $
+ * $Id: parsenodes.h,v 1.177 2002/05/17 01:19:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1439,6 +1439,7 @@ typedef struct VariableSetStmt
NodeTag type;
char *name;
List *args;
+ bool is_local; /* SET LOCAL */
} VariableSetStmt;
/* ----------------------
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index a889bd6c7b..46d8753ff4 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: datetime.h,v 1.29 2002/04/21 19:48:31 thomas Exp $
+ * $Id: datetime.h,v 1.30 2002/05/17 01:19:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -289,7 +289,7 @@ extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
extern int DecodeSpecial(int field, char *lowtoken, int *val);
extern int DecodeUnits(int field, char *lowtoken, int *val);
-extern void ClearDateCache(bool);
+extern bool ClearDateCache(bool, bool, bool);
extern int j2day(int jd);
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 6e0d580828..cc3ebd9220 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: elog.h,v 1.36 2002/04/21 00:22:52 ishii Exp $
+ * $Id: elog.h,v 1.37 2002/05/17 01:19:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -60,9 +60,9 @@ __attribute__((format(printf, 2, 3)));
extern int DebugFileOpen(void);
-extern bool check_server_min_messages(const char *lev);
-extern void assign_server_min_messages(const char *lev);
-extern bool check_client_min_messages(const char *lev);
-extern void assign_client_min_messages(const char *lev);
+extern const char *assign_server_min_messages(const char *newval,
+ bool doit, bool interactive);
+extern const char *assign_client_min_messages(const char *newval,
+ bool doit, bool interactive);
#endif /* ELOG_H */
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index a6eb17f6cf..ce1b10be83 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -4,13 +4,15 @@
* External declarations pertaining to backend/utils/misc/guc.c and
* backend/utils/misc/guc-file.l
*
- * $Id: guc.h,v 1.16 2002/03/24 04:31:09 tgl Exp $
+ * $Id: guc.h,v 1.17 2002/05/17 01:19:19 tgl Exp $
*/
#ifndef GUC_H
#define GUC_H
+#include "nodes/pg_list.h"
#include "utils/array.h"
+
/*
* Certain options can only be set at certain times. The rules are
* like this:
@@ -52,30 +54,45 @@ typedef enum
* The following type records the source of the current setting. A
* new setting can only take effect if the previous setting had the
* same or lower level. (E.g, changing the config file doesn't
- * override the postmaster command line.)
+ * override the postmaster command line.) Tracking the source allows us
+ * to process sources in any convenient order without affecting results.
+ * Sources <= PGC_S_OVERRIDE will set the default used by RESET, as well
+ * as the current value.
*/
typedef enum
{
PGC_S_DEFAULT = 0, /* wired-in default */
- PGC_S_FILE = 1, /* postgresql.conf */
- PGC_S_ARGV = 2, /* postmaster command line */
- PGC_S_DATABASE = 3, /* per-database setting */
- PGC_S_USER = 4, /* per-user setting */
- PGC_S_CLIENT = 5, /* from client (PGOPTIONS) */
- PGC_S_SESSION = 6, /* SET command */
- PGC_S_INFINITY = 100 /* can be used to avoid checks */
+ PGC_S_ENV_VAR = 1, /* postmaster environment variable */
+ PGC_S_FILE = 2, /* postgresql.conf */
+ PGC_S_ARGV = 3, /* postmaster command line */
+ PGC_S_DATABASE = 4, /* per-database setting */
+ PGC_S_USER = 5, /* per-user setting */
+ PGC_S_CLIENT = 6, /* from client (PGOPTIONS) */
+ PGC_S_OVERRIDE = 7, /* special case to forcibly set default */
+ PGC_S_SESSION = 8 /* SET command */
} GucSource;
extern void SetConfigOption(const char *name, const char *value,
GucContext context, GucSource source);
extern const char *GetConfigOption(const char *name);
+extern const char *GetConfigOptionResetString(const char *name);
extern void ProcessConfigFile(GucContext context);
-extern void ResetAllOptions(bool isStartup);
+extern void InitializeGUCOptions(void);
+extern void ResetAllOptions(void);
+extern void AtEOXact_GUC(bool isCommit);
extern void ParseLongOption(const char *string, char **name, char **value);
extern bool set_config_option(const char *name, const char *value,
- GucContext context, bool DoIt, GucSource source);
+ GucContext context, GucSource source,
+ bool isLocal, bool DoIt);
+extern void ShowGUCConfigOption(const char *name);
extern void ShowAllGUCConfig(void);
+extern void SetPGVariable(const char *name, List *args, bool is_local);
+extern void GetPGVariable(const char *name);
+extern void ResetPGVariable(const char *name);
+
+extern char *flatten_set_variable_args(const char *name, List *args);
+
extern void ProcessGUCArray(ArrayType *array, GucSource source);
extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value);
extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name);
diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h
index b5056e6ca8..a1ba131a92 100644
--- a/src/include/utils/pg_locale.h
+++ b/src/include/utils/pg_locale.h
@@ -2,7 +2,7 @@
*
* PostgreSQL locale utilities
*
- * $Header: /cvsroot/pgsql/src/include/utils/pg_locale.h,v 1.12 2002/04/03 05:39:33 petere Exp $
+ * $Id: pg_locale.h,v 1.13 2002/05/17 01:19:19 tgl Exp $
*
* Copyright (c) 2002, PostgreSQL Global Development Group
*
@@ -12,26 +12,23 @@
#ifndef _PG_LOCALE_
#define _PG_LOCALE_
-#include "postgres.h"
#include
-extern char * locale_messages;
-extern char * locale_monetary;
-extern char * locale_numeric;
-extern char * locale_time;
+extern char *locale_messages;
+extern char *locale_monetary;
+extern char *locale_numeric;
+extern char *locale_time;
-bool locale_messages_check(const char *proposed);
-bool locale_monetary_check(const char *proposed);
-bool locale_numeric_check(const char *proposed);
-bool locale_time_check(const char *proposed);
+extern const char *locale_messages_assign(const char *value,
+ bool doit, bool interactive);
+extern const char *locale_monetary_assign(const char *value,
+ bool doit, bool interactive);
+extern const char *locale_numeric_assign(const char *value,
+ bool doit, bool interactive);
+extern const char *locale_time_assign(const char *value,
+ bool doit, bool interactive);
-void locale_messages_assign(const char *value);
-void locale_monetary_assign(const char *value);
-void locale_numeric_assign(const char *value);
-void locale_time_assign(const char *value);
-
-bool chklocale(int category, const char *proposed);
-bool lc_collate_is_c(void);
+extern bool lc_collate_is_c(void);
/*
* Return the POSIX lconv struct (contains number/money formatting
diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/Connection.java
index 21f6c60ff3..96b85c78ce 100644
--- a/src/interfaces/jdbc/org/postgresql/Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/Connection.java
@@ -12,7 +12,7 @@ import org.postgresql.util.*;
import org.postgresql.core.*;
/*
- * $Id: Connection.java,v 1.46 2002/05/14 03:00:35 barry Exp $
+ * $Id: Connection.java,v 1.47 2002/05/17 01:19:19 tgl Exp $
*
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class.
@@ -951,7 +951,7 @@ public abstract class Connection
public int getTransactionIsolation() throws SQLException
{
clearWarnings();
- ExecSQL("show xactisolevel");
+ ExecSQL("show transaction isolation level");
SQLWarning warning = getWarnings();
if (warning != null)