Merge the last few variable.c configuration variables into the generic
authorTom Lane
Fri, 17 May 2002 01:19:19 +0000 (01:19 +0000)
committerTom Lane
Fri, 17 May 2002 01:19:19 +0000 (01:19 +0000)
GUC support.  It's now possible to set datestyle, timezone, and
client_encoding from postgresql.conf and per-database or per-user
settings.  Also, implement rollback of SET commands that occur in a
transaction that later fails.  Create a SET LOCAL var = value syntax
that sets the variable only for the duration of the current transaction.
All per previous discussions in pghackers.

42 files changed:
doc/src/sgml/ref/alter_database.sgml
doc/src/sgml/ref/alter_user.sgml
doc/src/sgml/ref/reset.sgml
doc/src/sgml/ref/set.sgml
doc/src/sgml/ref/set_session_auth.sgml
doc/src/sgml/ref/show.sgml
doc/src/sgml/release.sgml
doc/src/sgml/runtime.sgml
src/backend/access/transam/xact.c
src/backend/access/transam/xlog.c
src/backend/bootstrap/bootstrap.c
src/backend/catalog/namespace.c
src/backend/commands/dbcommands.c
src/backend/commands/user.c
src/backend/commands/variable.c
src/backend/main/main.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/adt/datetime.c
src/backend/utils/adt/pg_locale.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/error/elog.c
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/README [new file with mode: 0644]
src/backend/utils/misc/guc-file.l
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/access/xlog.h
src/include/catalog/namespace.h
src/include/commands/variable.h
src/include/miscadmin.h
src/include/nodes/parsenodes.h
src/include/utils/datetime.h
src/include/utils/elog.h
src/include/utils/guc.h
src/include/utils/pg_locale.h
src/interfaces/jdbc/org/postgresql/Connection.java

index a7e81d22d9ac296040b6684a9d7b99d853a1a9b9..76a4ac014afc40d70ebb30b540872927a1539a36 100644 (file)
@@ -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 
         configuration variable to the given value.  If
         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.
        
index d8461c4f4fbaaa8ccf5b8428c62c25a943b61d59..3cc82371aa9a3fac0a6ef0340a2a02a41a606936 100644 (file)
@@ -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.
        
 
index 69c1f861ee6e919c820f2bea8e53ba4bb085cecd..9f78d9df6c16b250fd987ec9fb87b22fc864528b 100644 (file)
@@ -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.
   
  
 
index 0dd4c44db160ec488fcc92b1a94b2ad7373e7709..f54f70c1979e0a1ef4336d9296bc80eebde0af0b 100644 (file)
@@ -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.
+  
 
-   
-    
-     CLIENT_ENCODING
-     NAMES
-     
-      
-       Sets the multibyte client encoding. The specified encoding
-       must be supported by the backend.
-      
+  
+   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.
+  
 
-      
-       This option is only available if
-       PostgreSQL is build with multibyte
-       support.
-      
-     
-    
+  
+   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:
+
+   
 
     
      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.
       
 
@@ -159,28 +201,47 @@ SET TIME ZONE { 'timezone' | LOCAL
       
 
       
-       Date format initialization may be done by:
+       SET DATESTYLE affects interpretation of
+       input and provides several standard output formats. For
+       applications needing different variations or tighter control
+       over input or output, consider using
+       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 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.
+    Setting the postmaster's PGDATESTYLE environment
+    variable.  (This will be overridden by any of the other methods.)
    
    
     Running postmaster using the option  to
-    set dates to the European convention.
+    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 DATESTYLE affects interpretation of
-       input and provides several standard output formats. For
-       applications needing different variations or tighter control
-       over input or output, consider using
-       the to_char family of
-       functions.
+       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.
    
   
  
index 7cd0d7d1ec7195713e5f23ac9044d77fa710a7fd..dfb20357005908eafaa2341f6fe5f7c7641784b7 100644 (file)
@@ -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 
+   as for the regular 
+   command.
+  
+
   
    The DEFAULT and RESET forms reset the session
    and current user identifiers to be the originally authenticated user
index 37e7e856525c57f88af04aaa0c60e2faf640a30e..b752f86ee6159c343fc826df6aded404d29ab91f 100644 (file)
@@ -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.
-       
-      
-     
     
    
  
index 72157ff271b5c03f182a077b5eac20510a88ee8b..889f2203f6916a89bbc9638857cb71064d571486 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -24,6 +24,9 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 
+Effects of SET within a transaction block now roll back if transaction aborts
+New SET LOCAL syntax sets a parameter for the life of the current transaction
+Datestyle, timezone, client_encoding can be set in postgresql.conf
 The last vestiges of support for type names datetime and timespan are gone; use timestamp and interval instead
 Rule names are now per-relation, not global; DROP RULE and COMMENT ON RULE syntax changes accordingly
 Readline and Zlib are now required by default and must be turned off explicitly if their use is not desired
@@ -36,8 +39,7 @@ Access privileges on functions
 Access privileges on procedural languages
 CREATE DATABASE has OWNER option so superuser can create DB for someone else
 Kerberos 5 support now works with Heimdal
-Database and user-specific session defaults of run-time configurations variables
-    (ALTER DATABASE ... SET and ALTER USER ... SET)
+Database and user-specific session defaults for run-time configuration variables (ALTER DATABASE ... SET and ALTER USER ... SET)
 ]]>
 
  
index 70131be3a27a856f85f8084a6e775a28bf540757..78d6dec0aaea943145a6a15ba1017e989ab4e62b 100644 (file)
@@ -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
index ca66b0afafab8332918ac2f086d9f17e79cf1dfa..d6176ec5c4734c3a1ce1b621cd71f97a3df90b82 100644 (file)
@@ -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:
 #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();
index eca4a5de5f83e3cba453d456112c109dd20a187e..77ad566ba89c1fc5b80676b02be07ff8d543e720 100644 (file)
@@ -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;
 }
 
 
index 51f432b1a0001526f20e50e07858d03aae0e4320..1a13786a04d10776d53d087d969394171b54f34e 100644 (file)
@@ -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;
            }
index 9e5002e37f169f27bc34e05ad7de8e69f5af931f..92c9306f184ab2db86344fcf6c580a7dc863b8e7 100644 (file)
@@ -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())
-   {
-       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)
+   if (interactive && IsTransactionState())
    {
-       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;
    }
 }
 
index 41f122767ad780c20c714009e84280f6d1c1cc93..bb53ad8b3bbdccfd4c6c74a665c87e9bc37091db 100644 (file)
@@ -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';
index 405a7ceaa2b9c7c24e08f5c43875f92bf97e141a..5398d718b63b3ad2ca076395c3eb1859a1f2793b 100644 (file)
@@ -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
index de42538bd63107c41fe4bce5de70450f4c10c881..03d7a6645778f2a28382001abd8fc978c54db85f 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #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
 #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.
+ * DATESTYLE
  */
-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!
+ * assign_datestyle: GUC assign_hook for datestyle
  */
-
-/* These get initialized from the "master" values in init/globals.c */
-static int DefaultDateStyle;
-static bool DefaultEuroDates;
-
-static bool
-parse_datestyle_internal(char *value)
+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");
-
-   return TRUE;
-}
-
-static bool
-parse_datestyle(List *args)
-{
-   int         rstat = FALSE;
-   List       *arg;
-   char       *value;
-
-   if (args == NULL)
-       return reset_datestyle();
+       ok = false;
 
-   Assert(IsA(args, List));
+   pfree(rawstring);
+   freeList(elemlist);
 
-   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);
-           }
+       if (interactive)
+           elog(ERROR, "SET DATESTYLE: conflicting specifications");
+       return NULL;
+   }
 
-           value = v->val.str;
-       }
-       else
-       {
-           elog(ERROR, "SET DATESTYLE argument is not valid");
-           value = NULL;
-       }
+   /*
+    * If we aren't going to do the assignment, just return OK indicator.
+    */
+   if (!doit)
+       return value;
 
-       rstat = parse_datestyle_internal(value);
+   /*
+    * Prepare the canonical string to return.  GUC wants it malloc'd.
+    */
+   result = (char *) malloc(32);
+   if (!result)
+       return NULL;
 
-       if (rstat != TRUE)
-           return rstat;
+   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 rstat;
+   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
- *
- */
-/* 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
+ * assign_timezone: GUC assign_hook for timezone
  */
-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;
-
-       Assert(IsA(arg, List));
-       p = lfirst(arg);
-       Assert(IsA(p, A_Const));
-
-       type = p->typename;
-       if (type != NULL)
+       const char *valueptr = value;
+       char       *val;
+       Interval   *interval;
+
+       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)
+           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)
            {
-               float8      time;
-
-               time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
-               CTimeZone = time * 3600;
+               CTimeZone = hours * 3600;
+               HasCTZSet = true;
            }
-
+       }
+       else if (strcasecmp(value, "UNKNOWN") == 0)
+       {
            /*
-            * We do not actually generate an integer constant in gram.y
-            * so this is not used...
+            * 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
             */
-           else if (typeOid == INT4OID)
-           {
-               int32       time;
-
-               time = p->val.val.ival;
-               CTimeZone = time * 3600;
-           }
-           else
+           if (doit)
            {
-               elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error");
+               if (tzbuf[0] == 'T')
+               {
+                   strcpy(tzbuf, "=");
+                   if (putenv(tzbuf) != 0)
+                       elog(ERROR, "Unable to clear TZ environment variable");
+                   tzset();
+               }
+               HasCTZSet = false;
            }
-
-           HasCTZSet = true;
        }
        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;
+
+   /*
+    * 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;
+}
 
-static bool
+/*
+ * 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)
-{
-   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);
-}
-
-static bool
-show_random_seed(void)
+bool
+assign_random_seed(double value, bool doit, bool interactive)
 {
-   elog(INFO, "Seed for random number generator is unavailable");
-   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
-reset_random_seed(void)
+const char *
+show_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
-
-   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;
+   int         old_encoding = 0;
 
-#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);
-#endif
-   return TRUE;
-}
-
-static bool
-show_client_encoding(void)
-{
-   elog(INFO, "Current client encoding is '%s'",
-        pg_get_client_encoding_name());
-   return TRUE;
-}
-
-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);
+   if (strcasecmp(value, pg_get_client_encoding_name()) != 0)
+       return NULL;
 #endif
-   return TRUE;
-}
 
-/* Called during MULTIBYTE backend startup ... */
-void
-set_default_client_encoding(void)
-{
-   reset_client_encoding();
+   return value;
 }
 
 
-static bool
-parse_server_encoding(List *args)
+const char *
+assign_server_encoding(const char *value, bool doit, bool interactive)
 {
-   elog(INFO, "SET SERVER_ENCODING is not supported");
-   return TRUE;
+   if (interactive)
+       elog(ERROR, "SET SERVER_ENCODING is not supported");
+   /* Pretend never to fail in noninteractive case */
+   return value;
 }
 
-static bool
+const char *
 show_server_encoding(void)
 {
-   elog(INFO, "Current server encoding is '%s'", GetDatabaseEncodingName());
-   return TRUE;
-}
-
-static bool
-reset_server_encoding(void)
-{
-   elog(INFO, "RESET SERVER_ENCODING is not supported");
-   return TRUE;
+   return GetDatabaseEncodingName();
 }
 
 
-static bool
-show_session_authorization(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, "Current session authorization is '%s'",
-        GetUserName(GetSessionUserId()));
-   return TRUE;
-}
+   Oid         usesysid;
+   char       *endptr;
+   char       *result;
 
+   usesysid = (Oid) strtoul(value, &endptr, 10);
 
-
-/* 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);
+   if (endptr != value && *endptr == '\0' && OidIsValid(usesysid))
+   {
+       /* use the numeric user ID */
+   }
    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;
+       HeapTuple   userTup;
 
-       if (args != NULL)
+       userTup = SearchSysCache(SHADOWNAME,
+                                PointerGetDatum(value),
+                                0, 0, 0);
+       if (!HeapTupleIsValid(userTup))
        {
-           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 [email protected]",
-                    name);
-               value = NULL;
-           }
-       }
-       else
-       {
-           value = NULL;
+           if (interactive)
+               elog(ERROR, "user \"%s\" does not exist", value);
+           return NULL;
        }
 
-       if (strcasecmp(name, "session_authorization") == 0)
-           SetSessionAuthorization(value);
-       else
-           SetConfigOption(name,
-                           value,
-                           (superuser() ? PGC_SUSET : PGC_USERSET),
-                           PGC_S_SESSION);
-   }
-   return;
-}
+       usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
 
-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();
+       ReleaseSysCache(userTup);
    }
-   else
-   {
-       const char *val = GetConfigOption(name);
 
-       elog(INFO, "%s is %s", name, val);
-   }
+   if (doit)
+       SetSessionAuthorization(usesysid);
+
+   result = (char *) malloc(32);
+   if (!result)
+       return NULL;
+
+   snprintf(result, 32, "%lu", (unsigned long) usesysid);
+
+   return result;
 }
 
-void
-ResetPGVariable(const char *name)
+const char *
+show_session_authorization(void)
 {
-   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());
 }
index 9c79e7b78d9476a1181fae32342e2d414f09301c..227fcc35e5e4a97e7b6851239b049a8ab86c3254 100644 (file)
@@ -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).
     */
index a3751d36984a3ede41e0e8cc625c4cb6c5b00c7e..909847dc856cc6d030a86b90ff1c96bdbdd22300 100644 (file)
@@ -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;
 }
index cf203243f1120364b53a7227d47052f8141080a4..1f0d175326b2ba39e80f246d74dec2d60feeee8f 100644 (file)
@@ -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;
 }
index bd3a7a0832b4844b3835c89f41c499709af9ca40..0009b9df2f03b432ff09bdec7076420b23d61af9 100644 (file)
@@ -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 = "session_authorization";
+                   n->name = "TRANSACTION ISOLATION LEVEL";
                    n->args = makeList1(makeStringConst($4, NULL));
-                   $$ = (Node *) n;
+                   $$ = 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($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";
+                   n->name = "timezone";
                    $$ = (Node *) n;
                }
-       | SHOW ALL
+       | SHOW TRANSACTION ISOLATION LEVEL
                {
                    VariableShowStmt *n = makeNode(VariableShowStmt);
-                   n->name  = "all";
+                   n->name = "TRANSACTION ISOLATION LEVEL";
                    $$ = (Node *) n;
                }
-       | SHOW TRANSACTION ISOLATION LEVEL
+       | SHOW SESSION AUTHORIZATION
+               {
+                   VariableShowStmt *n = makeNode(VariableShowStmt);
+                   n->name = "session_authorization";
+                   $$ = (Node *) n;
+               }
+       | SHOW ALL
                {
                    VariableShowStmt *n = makeNode(VariableShowStmt);
-                   n->name  = "XactIsoLevel";
+                   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;
                }
        ;
index a3a8f2521e5cfb6178aa596da7bc5a15f0d89dc8..1513f13878dac7d42b1243bb79c7a8a5ef7c87af 100644 (file)
@@ -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;
            }
index eaf626ace955bf116c73b2d6618b55a75a36a20a..53bf45dce9c796870a916bcb78c80236b18d7043 100644 (file)
@@ -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");
    }
 
    /*
index 9a9c062559e7a696eea76af281031cc2105cb297..e72d8dfccf7c3d62870e10af2fff7e29401c6946 100644 (file)
@@ -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;
 
index 1a908d9d6b7d15801f1e383b8c964f659322b942..d6e0358e817379399b7f314164535ce2161c526f 100644 (file)
@@ -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;
 }
index c5c8d312d3f6c5f041d3bc31d2f904e043538f5b..ba962ac8b152d177185db983fc94b872ee63fd45 100644 (file)
@@ -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
  *
  */
 
 #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
-}
+/* GUC assign hooks */
 
-bool locale_monetary_check(const char *proposed)
+static const char *
+locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
 {
-   return chklocale(LC_MONETARY, proposed);
-}
+   if (doit)
+   {
+       if (!setlocale(category, value))
+           return NULL;
+   }
+   else
+   {
+       char *save;
 
-bool locale_numeric_check(const char *proposed)
-{
-   return chklocale(LC_NUMERIC, proposed);
-}
+       save = setlocale(category, NULL);
+       if (!save)
+           return NULL;
 
-bool locale_time_check(const char *proposed)
-{
-   return chklocale(LC_TIME, proposed);
-}
+       if (!setlocale(category, value))
+           return NULL;
 
-/* GUC assign hooks */
+       setlocale(category, save);
+   }
+   return value;
+}
 
-void locale_messages_assign(const char *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)
-{
-   setlocale(LC_MONETARY, value);
-}
-
-void locale_numeric_assign(const char *value)
+const char *
+locale_monetary_assign(const char *value, bool doit, bool interactive)
 {
-   setlocale(LC_NUMERIC, value);
+   return locale_xxx_assign(LC_MONETARY, value, doit, interactive);
 }
 
-void locale_time_assign(const char *value)
+const char *
+locale_numeric_assign(const char *value, bool doit, bool interactive)
 {
-   setlocale(LC_TIME, value);
+   return locale_xxx_assign(LC_NUMERIC, value, doit, interactive);
 }
 
-
-/*
- * 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)
+const char *
+locale_time_assign(const char *value, bool doit, bool interactive)
 {
-   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;
index 78cb6306e02993fade598c792c64ca73a1da2e08..88528b9a0652745749fb13f7023820534bd68ecf 100644 (file)
@@ -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;
 }
 
index 572e21ba8310adef6756cf4d3dbd2dea3e7a8b26..a1813b67b83830c68d7428c75d31fad3b0dd5ac9 100644 (file)
@@ -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)
-{
-   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)
+const char *
+assign_server_min_messages(const char *newval,
+                          bool doit, bool interactive)
 {
-   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)
-{
-   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)
+const char *
+assign_client_min_messages(const char *newval,
+                          bool doit, bool interactive)
 {
-   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 */
 }
index 4cc9d396c70b470a460396d3261dfea903fac9e7..fd3f191d5cdd5f1af2c76b762617d6ee8e17bd19 100644 (file)
@@ -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);
index 95974c6d6a6ee29080ff2a9303c97947f49a9ded..817c87c80a0aca256e829a5baf7565e6a5ac9cc4 100644 (file)
@@ -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 (file)
index 0000000..fe252d5
--- /dev/null
@@ -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.
index fe6cf89ac0c846949274c7c793f289e66a1807ec..2f50b4b55c6f21ccb4b6c7b8bc3e50f24ae90b77 100644 (file)
@@ -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);
index f917af9a422f57fb1e8bcbbd48ca4977dd999f95..f1d4e8ee29199c72c9900c7aed376514abece83c 100644 (file)
@@ -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,13 +59,10 @@ extern bool FixBTree;
 #ifdef HAVE_SYSLOG
 extern char *Syslog_facility;
 extern char *Syslog_ident;
-static bool check_facility(const char *facility);
-#endif
-
-static char *default_iso_level_string;
 
-static bool check_defaultxactisolevel(const char *value);
-static void assign_defaultxactisolevel(const char *value);
+static const char *assign_facility(const char *facility,
+                                  bool doit, bool interactive);
+#endif
 
 /*
  * 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,477 +691,1020 @@ 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,
-       "$libdir", NULL, NULL
+       { "DateStyle", PGC_USERSET, GUC_LIST_INPUT }, &datestyle_string,
+       "ISO, US", assign_datestyle, show_datestyle
    },
 
    {
-       "search_path", PGC_USERSET, PGC_S_DEFAULT, &namespace_search_path,
-       "$user,public", check_search_path, assign_search_path
+       { "default_transaction_isolation", PGC_USERSET }, &default_iso_level_string,
+       "read committed", assign_defaultxactisolevel, NULL
    },
 
    {
-       "krb_server_keyfile", PGC_POSTMASTER, PGC_S_DEFAULT, &pg_krb_server_keyfile,
+       { "dynamic_library_path", PGC_SUSET }, &Dynamic_library_path,
+       "$libdir", NULL, NULL
+   },
+
+   {
+       { "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 }, &locale_monetary,
+       "", locale_monetary_assign, NULL
+   },
+
+   {
+       { "lc_numeric", PGC_USERSET }, &locale_numeric,
+       "", locale_numeric_assign, NULL
+   },
+
+   {
+       { "lc_time", PGC_USERSET }, &locale_time,
+       "", locale_time_assign, NULL
    },
 
    {
-       "lc_monetary", PGC_USERSET, PGC_S_DEFAULT, &locale_monetary,
-       "", locale_monetary_check, locale_monetary_assign
+       { "search_path", PGC_USERSET, GUC_LIST_INPUT | GUC_LIST_QUOTE },
+       &namespace_search_path,
+       "$user,public", assign_search_path, NULL
    },
 
    {
-       "lc_numeric", PGC_USERSET, PGC_S_DEFAULT, &locale_numeric,
-       "", locale_numeric_check, locale_numeric_assign
+       { "server_encoding", PGC_USERSET }, &server_encoding_string,
+       "SQL_ASCII", assign_server_encoding, show_server_encoding
    },
 
    {
-       "lc_time", PGC_USERSET, PGC_S_DEFAULT, &locale_time,
-       "", locale_time_check, locale_time_assign
+       { "server_min_messages", PGC_USERSET }, &server_min_messages_str,
+       server_min_messages_str_default, assign_server_min_messages, 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
+       { "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;
-
-   Assert(name);
+static struct config_generic **guc_variables;
+static int num_guc_variables;
 
-   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;
-       }
-
-   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;
-       }
+static bool guc_dirty;         /* TRUE if need to do commit/abort work */
 
-   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;
-       }
+static char *guc_string_workspace; /* for avoiding memory leaks */
 
-   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;
-
-           if (conf->default_val == NULL &&
-               conf->boot_default_val)
-           {
-               str = strdup(conf->boot_default_val);
-               if (str == NULL)
-                   elog(ERROR, "out of memory");
-               conf->default_val = str;
-           }
-           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;
-       }
+       conf->gen.vartype = PGC_STRING;
+       num_vars++;
    }
-}
 
+   guc_vars = (struct config_generic **)
+       malloc(num_vars * sizeof(struct config_generic *));
+   if (!guc_vars)
+       elog(PANIC, "out of memory");
 
+   num_vars = 0;
 
-/*
- * Try to interpret value as boolean value.  Valid values are: true,
- * false, yes, no, on, off, 1, 0.  If the string parses okay, return
- * true, else false.  If result is not NULL, return the parsing result
- * there.
- */
-static bool
-parse_bool(const char *value, bool *result)
-{
-   size_t      len = strlen(value);
+   for (i = 0; ConfigureNamesBool[i].gen.name; i++)
+       guc_vars[num_vars++] = & ConfigureNamesBool[i].gen;
 
-   if (strncasecmp(value, "true", len) == 0)
-   {
-       if (result)
-           *result = true;
-   }
-   else if (strncasecmp(value, "false", len) == 0)
-   {
-       if (result)
-           *result = false;
-   }
+   for (i = 0; ConfigureNamesInt[i].gen.name; i++)
+       guc_vars[num_vars++] = & ConfigureNamesInt[i].gen;
 
-   else if (strncasecmp(value, "yes", len) == 0)
-   {
-       if (result)
-           *result = true;
-   }
-   else if (strncasecmp(value, "no", len) == 0)
-   {
-       if (result)
-           *result = false;
-   }
+   for (i = 0; ConfigureNamesReal[i].gen.name; i++)
+       guc_vars[num_vars++] = & ConfigureNamesReal[i].gen;
 
-   else if (strcasecmp(value, "on") == 0)
-   {
-       if (result)
-           *result = true;
-   }
-   else if (strcasecmp(value, "off") == 0)
-   {
-       if (result)
-           *result = false;
-   }
+   for (i = 0; ConfigureNamesString[i].gen.name; i++)
+       guc_vars[num_vars++] = & ConfigureNamesString[i].gen;
 
-   else if (strcasecmp(value, "1") == 0)
-   {
-       if (result)
-           *result = true;
-   }
-   else if (strcasecmp(value, "0") == 0)
-   {
-       if (result)
-           *result = false;
-   }
+   qsort((void *) guc_vars, num_vars, sizeof(struct config_generic *),
+         guc_var_compare);
 
-   else
-       return false;
-   return true;
+   if (guc_variables)
+       free(guc_variables);
+   guc_variables = guc_vars;
+   num_guc_variables = num_vars;
 }
 
 
-
 /*
- * Try to parse value as an integer.  The accepted formats are the
- * usual decimal, octal, or hexadecimal formats.  If the string parses
- * okay, return true, else false.  If result is not NULL, return the
- * value there.
+ * Look up option NAME. If it exists, return a pointer to its record,
+ * else return NULL.
  */
-static bool
-parse_int(const char *value, int *result)
+static struct config_generic *
+find_option(const char *name)
 {
-   long        val;
-   char       *endptr;
+   const char **key = &name;
+   struct config_generic **res;
 
-   errno = 0;
-   val = strtol(value, &endptr, 0);
-   if (endptr == value || *endptr != '\0' || errno == ERANGE
-#ifdef HAVE_LONG_INT_64
-   /* if long > 32 bits, check for overflow of int4 */
-       || val != (long) ((int32) val)
-#endif
-       )
-       return false;
-   if (result)
-       *result = (int) val;
-   return true;
-}
+   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;
+}
 
 
 /*
- * Try to parse value as a floating point constant in the usual
- * format. If the value parsed okay return true, else false.  If
- * result is not NULL, return the semantic value there.
+ * comparator for qsorting and bsearching guc_variables array
  */
-static bool
-parse_real(const char *value, double *result)
+static int
+guc_var_compare(const void *a, const void *b)
 {
-   double      val;
-   char       *endptr;
+   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;
 
-   errno = 0;
-   val = strtod(value, &endptr);
-   if (endptr == value || *endptr != '\0' || errno == ERANGE)
-       return false;
-   if (result)
-       *result = val;
-   return true;
-}
+   /*
+    * 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);
+}
 
 
 /*
- * 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
- * function is being called so it can apply the access restrictions
- * properly.
- *
- * If value is NULL, set the option to its default value. If the
- * parameter DoIt is false then don't really set the option but do all
- * 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.
- *
- * See also SetConfigOption for an external interface.
+ * Initialize GUC options during program startup.
  */
-bool
-set_config_option(const char *name, const char *value,
-                 GucContext context, bool DoIt, GucSource source)
+void
+InitializeGUCOptions(void)
 {
-   struct config_generic *record;
-   enum config_type type;
-   int         elevel;
-   bool        makeDefault;
-
-   if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
-       elevel = DEBUG1;
-   else if (guc_session_init)
-       elevel = INFO;
-   else
-       elevel = ERROR;
-
-   type = find_option(name, &record);
-   if (type == PGC_NONE)
-   {
-       elog(elevel, "'%s' is not a valid option name", name);
-       return false;
-   }
+   int         i;
+   char       *env;
 
-   if (record->source > source)
-   {
-       elog(DEBUG2, "setting %s refused because previous source is higher",
-           name);
-       return false;
-   }
-   makeDefault = source < PGC_S_SESSION;
+   /*
+    * Build sorted array of all GUC variables.
+    */
+   build_guc_variables();
 
    /*
-    * 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.
+    * 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...
     */
-   switch (record->context)
+   for (i = 0; i < num_guc_variables; i++)
    {
-       case PGC_POSTMASTER:
-           if (context == PGC_SIGHUP)
-               return true;
-           if (context != PGC_POSTMASTER)
-               elog(ERROR, "'%s' cannot be changed after server start", name);
-           break;
-       case PGC_SIGHUP:
-           if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
-               elog(ERROR, "'%s' cannot be changed now", name);
+       struct config_generic *gconf = guc_variables[i];
 
-           /*
-            * Hmm, the idea of the SIGHUP context is "ought to be global,
-            * but can be changed after postmaster start". But there's
-            * nothing that prevents a crafty administrator from sending
-            * SIGHUP signals to individual backends only.
-            */
-           break;
-       case PGC_BACKEND:
-           if (context == PGC_SIGHUP)
+       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:
            {
-               /*
-                * If a PGC_BACKEND parameter is changed in the config
-                * file, we want to accept the new value in the postmaster
-                * (whence it will propagate to subsequently-started
-                * backends), but ignore it in existing backends.  This is
-                * a tad klugy, but necessary because we don't re-read the
-                * config file during backend start.
-                */
-               if (IsUnderPostmaster)
-                   return true;
+               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");
+
+               /*
+                * 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;
+           }
+       }
+   }
+}
+
+
+/*
+ * 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,
+ * false, yes, no, on, off, 1, 0.  If the string parses okay, return
+ * true, else false.  If result is not NULL, return the parsing result
+ * there.
+ */
+static bool
+parse_bool(const char *value, bool *result)
+{
+   size_t      len = strlen(value);
+
+   if (strncasecmp(value, "true", len) == 0)
+   {
+       if (result)
+           *result = true;
+   }
+   else if (strncasecmp(value, "false", len) == 0)
+   {
+       if (result)
+           *result = false;
+   }
+
+   else if (strncasecmp(value, "yes", len) == 0)
+   {
+       if (result)
+           *result = true;
+   }
+   else if (strncasecmp(value, "no", len) == 0)
+   {
+       if (result)
+           *result = false;
+   }
+
+   else if (strcasecmp(value, "on") == 0)
+   {
+       if (result)
+           *result = true;
+   }
+   else if (strcasecmp(value, "off") == 0)
+   {
+       if (result)
+           *result = false;
+   }
+
+   else if (strcasecmp(value, "1") == 0)
+   {
+       if (result)
+           *result = true;
+   }
+   else if (strcasecmp(value, "0") == 0)
+   {
+       if (result)
+           *result = false;
+   }
+
+   else
+       return false;
+   return true;
+}
+
+
+
+/*
+ * Try to parse value as an integer.  The accepted formats are the
+ * usual decimal, octal, or hexadecimal formats.  If the string parses
+ * okay, return true, else false.  If result is not NULL, return the
+ * value there.
+ */
+static bool
+parse_int(const char *value, int *result)
+{
+   long        val;
+   char       *endptr;
+
+   errno = 0;
+   val = strtol(value, &endptr, 0);
+   if (endptr == value || *endptr != '\0' || errno == ERANGE
+#ifdef HAVE_LONG_INT_64
+   /* if long > 32 bits, check for overflow of int4 */
+       || val != (long) ((int32) val)
+#endif
+       )
+       return false;
+   if (result)
+       *result = (int) val;
+   return true;
+}
+
+
+
+/*
+ * Try to parse value as a floating point constant in the usual
+ * format. If the value parsed okay return true, else false.  If
+ * result is not NULL, return the semantic value there.
+ */
+static bool
+parse_real(const char *value, double *result)
+{
+   double      val;
+   char       *endptr;
+
+   errno = 0;
+   val = strtod(value, &endptr);
+   if (endptr == value || *endptr != '\0' || errno == ERANGE)
+       return false;
+   if (result)
+       *result = val;
+   return true;
+}
+
+
+
+/*
+ * 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.  The context and source parameters indicate in which context this
+ * function is being called so it can apply the access restrictions
+ * properly.
+ *
+ * If value is NULL, set the option to its default value. If the
+ * parameter DoIt is false then don't really set the option but do all
+ * 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 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, GucSource source,
+                 bool isLocal, bool DoIt)
+{
+   struct config_generic *record;
+   int         elevel;
+   bool        interactive;
+   bool        makeDefault;
+
+   if (context == PGC_SIGHUP || source == PGC_S_DEFAULT)
+       elevel = DEBUG1;
+   else if (source == PGC_S_DATABASE || source == PGC_S_USER)
+       elevel = INFO;
+   else
+       elevel = ERROR;
+
+   record = find_option(name);
+   if (record == NULL)
+   {
+       elog(elevel, "'%s' is not a valid option name", name);
+       return false;
+   }
+
+   /*
+    * 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 and
+    * return true.
+    */
+   switch (record->context)
+   {
+       case PGC_POSTMASTER:
+           if (context == PGC_SIGHUP)
+               return true;
+           if (context != PGC_POSTMASTER)
+           {
+               elog(elevel, "'%s' cannot be changed after server start",
+                    name);
+               return false;
+           }
+           break;
+       case PGC_SIGHUP:
+           if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
+           {
+               elog(elevel, "'%s' cannot be changed now", name);
+               return false;
+           }
+
+           /*
+            * Hmm, the idea of the SIGHUP context is "ought to be global,
+            * but can be changed after postmaster start". But there's
+            * nothing that prevents a crafty administrator from sending
+            * SIGHUP signals to individual backends only.
+            */
+           break;
+       case PGC_BACKEND:
+           if (context == PGC_SIGHUP)
+           {
+               /*
+                * If a PGC_BACKEND parameter is changed in the config
+                * file, we want to accept the new value in the postmaster
+                * (whence it will propagate to subsequently-started
+                * backends), but ignore it in existing backends.  This is
+                * a tad klugy, but necessary because we don't re-read the
+                * config file during backend start.
+                */
+               if (IsUnderPostmaster)
+                   return true;
+           }
+           else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
+           {
+               elog(elevel, "'%s' cannot be set after connection start",
+                    name);
+               return false;
+           }
+           break;
+       case PGC_SUSET:
+           if (context == PGC_USERSET || context == PGC_BACKEND)
+           {
+               elog(elevel, "'%s': permission denied", name);
+               return false;
            }
-           else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
-               elog(ERROR, "'%s' cannot be set after connection start", name);
-           break;
-       case PGC_SUSET:
-           if (context == PGC_USERSET || context == PGC_BACKEND)
-               elog(ERROR, "permission denied");
            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, &newval))
+                   {
+                       elog(elevel, "option '%s' requires a boolean value",
+                            name);
+                       return false;
+                   }
+               }
+               else
+               {
+                   newval = conf->reset_val;
+                   source = conf->gen.reset_source;
+               }
 
-                   if (!parse_bool(value, &boolval))
+               if (conf->assign_hook)
+                   if (!(*conf->assign_hook) (newval, DoIt, interactive))
                    {
-                       elog(elevel, "option '%s' requires a boolean value", name);
+                       elog(elevel, "invalid value for option '%s': %d",
+                            name, (int) newval);
                        return false;
                    }
-                   /* no parse_hook needed for booleans */
+
+               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))
+               }
+               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, intval);
+                            name, newval);
                        return false;
                    }
+
+               if (DoIt || makeDefault)
+               {
                    if (DoIt)
                    {
-                       if (conf->assign_hook)
-                           (conf->assign_hook) (intval);
-                       *conf->variable = intval;
-                       if (makeDefault)
-                           conf->default_val = intval;
-                       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;
            }
@@ -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))
+               }
+               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': %g",
-                            name, dval);
+                            name, newval);
                        return false;
                    }
+
+               if (DoIt || makeDefault)
+               {
                    if (DoIt)
                    {
-                       if (conf->assign_hook)
-                           (conf->assign_hook) (dval);
-                       *conf->variable = dval;
-                       if (makeDefault)
-                           conf->default_val = dval;
-                       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;
            }
@@ -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))
+                   newval = strdup(value);
+                   if (newval == NULL)
+                   {
+                       elog(elevel, "out of memory");
+                       return false;
+                   }
+               }
+               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);
+                            name, value ? value : "");
                        return false;
                    }
-                   if (DoIt)
+                   else if (hookresult != newval)
                    {
-                       char       *str;
+                       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;
 
-                       str = strdup(value);
-                       if (str == NULL)
+               if (DoIt || makeDefault)
+               {
+                   if (DoIt)
+                   {
+                       SET_STRING_VARIABLE(conf, newval);
+                       conf->gen.source = source;
+                   }
+                   if (makeDefault)
+                   {
+                       if (conf->gen.reset_source <= source)
                        {
-                           elog(elevel, "out of memory");
-                           return false;
+                           SET_STRING_RESET_VAL(conf, newval);
+                           conf->gen.reset_source = source;
                        }
-                       if (conf->assign_hook)
-                           (conf->assign_hook) (str);
-                       if (*conf->variable)
-                           free(*conf->variable);
-                       *conf->variable = str;
-                       if (makeDefault)
+                       if (conf->gen.session_source <= source)
                        {
-                           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;
+                           SET_STRING_SESSION_VAL(conf, newval);
+                           conf->gen.session_source = source;
                        }
-                       conf->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 (DoIt)
-               {
-                   char       *str;
-
-                   if (!conf->default_val && conf->boot_default_val)
+                   else if (isLocal)
                    {
-                       str = strdup(conf->boot_default_val);
-                       if (str == NULL)
-                       {
-                           elog(elevel, "out of memory");
-                           return false;
-                       }
-                       conf->default_val = str;
+                       conf->gen.status |= GUC_HAVE_LOCAL;
+                       guc_dirty = true;
                    }
-                   str = strdup(conf->default_val);
-                   if (str == NULL)
+                   else
                    {
-                       elog(elevel, "out of memory");
-                       return false;
+                       SET_STRING_TENTATIVE_VAL(conf, newval);
+                       conf->gen.tentative_source = source;
+                       conf->gen.status |= GUC_HAVE_TENTATIVE;
+                       guc_dirty = true;
                    }
-                   if (conf->assign_hook)
-                       (conf->assign_hook) (str);
-                   if (*conf->variable)
-                       free(*conf->variable);
-                   *conf->variable = str;
+               }
+               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;
+           return ((struct config_string *) record)->reset_val;
+   }
+   return NULL;
+}
 
-       default:
-           val = "???";
+
+
+/*
+ * 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;
+       }
    }
-   elog(INFO, "%s is %s", record->name, val);
+
+   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];
+
+       if ((conf->flags & GUC_NO_SHOW_ALL) == 0)
+           _ShowOption(conf);
+   }
+}
 
-   for (i = 0; ConfigureNamesInt[i].name; i++)
-       _ShowOption(PGC_INT, (struct config_generic *) & ConfigureNamesInt[i]);
+static void
+_ShowOption(struct config_generic *record)
+{
+   char        buffer[256];
+   const char *val;
 
-   for (i = 0; ConfigureNamesReal[i].name; i++)
-       _ShowOption(PGC_REAL, (struct config_generic *) & ConfigureNamesReal[i]);
+   switch (record->vartype)
+   {
+       case PGC_BOOL:
+           {
+               struct config_bool *conf = (struct config_bool *) record;
 
-   for (i = 0; ConfigureNamesString[i].name; i++)
-       _ShowOption(PGC_STRING, (struct config_generic *) & ConfigureNamesString[i]);
-}
+               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)
-{
-   return (strcasecmp(value, "read committed") == 0
-           || strcasecmp(value, "serializable") == 0)
-       ? true : false;
-}
+#endif
 
 
-static void
-assign_defaultxactisolevel(const char *value)
+static const char *
+assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
 {
-   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;
index 843ad5ce1583671d568b65fe0e29afeb3c44069f..3fae561d7c6b41ae6ef77019ab295e18d7013c92 100644 (file)
 #
 #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'
index 9252a8d324a10968a9f01d6cf362f4a043623c30..92e74b88d7e2b6430a56349a3682a9fe91088706 100644 (file)
@@ -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 */
index 545b1a1383aedcb189764d45292b3ec6f627f414..8fe62acb0e11d13713796be772ff6e228ac6e670 100644 (file)
@@ -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);
index f4f12c97127bcca9bfb51a32e7c964fa9ab2bfe2..bdca5c88a92b9a1ae335a02bbcb7a8a80d4b1c03 100644 (file)
@@ -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 */
index 09e1c0fe635adcb9d772719c52688d7faa4bad1e..2e5fc76bb7d2149915530c24bae5cb8e95b315c6 100644 (file)
@@ -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);
 
index 0c5672dd67782c34decdc974d786b0c4b0b0a379..a0bf47d7ed061a2ada424897f9b9a5b6235cf60d 100644 (file)
@@ -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;
 
 /* ----------------------
index a889bd6c7bcc728cf92ce41ac980600daf4abbe1..46d8753ff43fd65dcc23ac590a54d99e15bfae09 100644 (file)
@@ -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);
 
index 6e0d58082807492649fa0533229bf44e30311136..cc3ebd9220e6d3c53945f3d7228476f1a63371eb 100644 (file)
@@ -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 */
index a6eb17f6cfe84791bc34d3bbc58baa038cdb92ab..ce1b10be839ea551dfaa004a09924fcb51468d5d 100644 (file)
@@ -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);
index b5056e6ca8064df2e63eaa2bcaa2b701f20b4f06..a1ba131a92ad1f0ae45a7ede26d10fc69e537eb4 100644 (file)
@@ -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
  *
 #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;
-
-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);
-
-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 char *locale_messages;
+extern char *locale_monetary;
+extern char *locale_numeric;
+extern char *locale_time;
+
+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);
+
+extern bool lc_collate_is_c(void);
 
 /*
  * Return the POSIX lconv struct (contains number/money formatting
index 21f6c60ff3685701a4688ce11909ba20e065c17b..96b85c78ce7ade805f55d302482e3647e127756b 100644 (file)
@@ -12,7 +12,7 @@ import org.postgresql.util.*;
 import org.postgresql.core.*;\r
 \r
 /*\r
- * $Id: Connection.java,v 1.46 2002/05/14 03:00:35 barry Exp $\r
+ * $Id: Connection.java,v 1.47 2002/05/17 01:19:19 tgl Exp $\r
  *\r
  * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or\r
  * JDBC2 versions of the Connection class.\r
@@ -951,7 +951,7 @@ public abstract class Connection
         public int getTransactionIsolation() throws SQLException\r
         {\r
                 clearWarnings();\r
-                ExecSQL("show xactisolevel");\r
+                ExecSQL("show transaction isolation level");\r
 \r
                 SQLWarning warning = getWarnings();\r
                 if (warning != null)\r