OSDN Git Service

Merge the last few variable.c configuration variables into the generic
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 17 May 2002 01:19:19 +0000 (01:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 a7e81d2..76a4ac0 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.2 2002/04/23 02:07:15 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.3 2002/05/17 01:19:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -28,10 +28,9 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea
    <command>ALTER DATABASE</command> is used to change the session
    default of a run-time configuration variable for a
    <productname>PostgreSQL</productname> database. Whenever a new
-   session is subsequently started in that database, <literal>SET
-   <replaceable>variable</replaceable> TO
-   <replaceable>value</replaceable></literal> 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 <filename>postgresql.conf</>
    or has been received from the postmaster.
   </para>
@@ -64,7 +63,8 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replacea
         configuration variable to the given value.  If
         <replaceable>value</replaceable> is <literal>DEFAULT</literal>
         or, equivalently, <literal>RESET</literal> 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 <literal>RESET
         ALL</literal> to clear all settings.
        </para>
index d8461c4..3cc8237 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.21 2002/03/22 19:20:36 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.22 2002/05/17 01:19:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -48,14 +48,13 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea
   </para>
 
   <para>
-   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, <literal>SET
-   <replaceable>variable</replaceable> TO
-   <replaceable>value</replaceable></literal> 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 <filename>postgresql.conf</>
+   or has been received from the postmaster.
+   Ordinary users can change their own session defaults.
+   Superusers can change anyone's session defaults.
   </para>
 
   <refsect2>
@@ -135,12 +134,12 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable> RESET <replacea
       <term><replaceable>value</replaceable></term>
       <listitem>
        <para>
-        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
         <replaceable>value</replaceable> is <literal>DEFAULT</literal>
         or, equivalently, <literal>RESET</literal> 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
         <literal>RESET ALL</literal> to clear all settings.
        </para>
 
index 69c1f86..9f78d9d 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.13 2001/12/08 03:24:39 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/reset.sgml,v 1.14 2002/05/17 01:19:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -37,7 +37,7 @@ RESET ALL
       <term>ALL</term>
       <listitem>
        <para>
-        Resets all run-time parameters to default values.
+        Resets all settable run-time parameters to default values.
        </para>
       </listitem>
      </varlistentry>
@@ -53,11 +53,18 @@ RESET ALL
    <command>RESET</command> restores run-time parameters to their
    default values. Refer to
    <xref linkend="sql-set" endterm="sql-set-title">
-   for details. <command>RESET</command> is an alternate form for
+   for details. <command>RESET</command> is an alternate spelling for
 
    <synopsis>
 SET <replaceable class="parameter">variable</replaceable> TO DEFAULT
    </synopsis>
+
+   The default value is defined as the value that the variable would
+   have had, had no <command>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
+   <citetitle>Administrator's Guide</citetitle> for details.
   </para>
  </refsect1>
 
index 0dd4c44..f54f70c 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.59 2002/04/21 19:02:39 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.60 2002/05/17 01:19:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -14,14 +14,40 @@ PostgreSQL documentation
  </refnamediv>
  <refsynopsisdiv>
   <synopsis>
-SET <replaceable class="PARAMETER">variable</replaceable> { TO | = } { <replaceable class="PARAMETER">value</replaceable> | '<replaceable class="PARAMETER">value</replaceable>' | DEFAULT }
-SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL | DEFAULT }
+SET [ SESSION | LOCAL ] <replaceable class="PARAMETER">variable</replaceable> { TO | = } { <replaceable class="PARAMETER">value</replaceable> | '<replaceable class="PARAMETER">value</replaceable>' | DEFAULT }
+SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</replaceable> | LOCAL | DEFAULT }
   </synopsis>
 
   <refsect2 id="R2-SQL-SET-1">
    <title>Inputs</title>
    <para>
     <variablelist>
+
+     <varlistentry>
+      <term><option>SESSION</></term>
+      <listitem>
+       <para>
+        Specifies that the command takes effect for the current session.
+       (This is the default if neither <option>SESSION</> nor
+       <option>LOCAL</> appears.)
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><option>LOCAL</></term>
+      <listitem>
+       <para>
+        Specifies that the command takes effect for only the current
+       transaction.  After <command>COMMIT</> or <command>ROLLBACK</>,
+       the session-level setting takes effect again.  Note that
+       <command>SET LOCAL</> will appear to have no effect if it's
+       executed outside a <command>BEGIN</> block, since the transaction
+       will end immediately.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><replaceable class="PARAMETER">variable</replaceable></term>
       <listitem>
@@ -30,6 +56,7 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
        </para>
       </listitem>
      </varlistentry>
+
      <varlistentry>
       <term><replaceable class="PARAMETER">value</replaceable></term>
       <listitem>
@@ -49,34 +76,49 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
  
  <refsect1 id="R1-SQL-SET-1">
   <title>Description</title>
+
   <para>
    The <command>SET</command> command changes run-time configuration
-   parameters. The following parameters can be altered:
+   parameters.  Many of the run-time parameters listed in the
+   <citetitle>Administrator's Guide</citetitle> can be changed on-the-fly
+   with <command>SET</command>.  (But some require superuser privileges
+   to change, and others cannot be changed after server or session start.)
+   Note that <command>SET</command> only affects the value used by the
+   current session.
+  </para>
 
-   <variablelist>
-    <varlistentry>
-     <term>CLIENT_ENCODING</term>
-     <term>NAMES</term>
-     <listitem>
-      <para>
-       Sets the multibyte client encoding. The specified encoding
-       must be supported by the backend.
-      </para>
+  <para>
+   If <command>SET</command> or <command>SET SESSION</command> is issued
+   within a transaction that is later aborted, the effects of the
+   <command>SET</command> command disappear when the transaction is rolled
+   back.  (This behavior represents a change from
+   <productname>PostgreSQL</productname> versions prior to 7.3, where
+   the effects of <command>SET</command> 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
+   <command>SET</command>.
+  </para>
 
-      <para>
-       This option is only available if
-       <productname>PostgreSQL</productname> is build with multibyte
-       support.
-      </para>
-     </listitem>
-    </varlistentry>
+  <para>
+   The effects of <command>SET LOCAL</command> last only till the end of
+   the current transaction, whether committed or not.  A special case is
+   <command>SET</command> followed by <command>SET LOCAL</command> within
+   a single transaction: the <command>SET LOCAL</command> value will be
+   seen until the end of the transaction, but afterwards (if the transaction
+   is committed) the <command>SET</command> value will take effect.
+  </para>
+
+  <para>
+   Here are additional details about a few of the parameters that can be set:
+
+   <variablelist>
 
     <varlistentry>
      <term>DATESTYLE</term>
      <listitem>
       <para>
        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.
       </para>
 
@@ -159,28 +201,47 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
       </para>
 
       <para>
-       Date format initialization may be done by:
+       <command>SET DATESTYLE</command> 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 <function>to_char</function> family of
+       functions.
+      </para>
+
+      <para>
+       There are several now-deprecated means for setting the datestyle
+       in addition to the normal methods of setting it via <command>SET</> or
+       a configuration-file entry:
        <simplelist>
        <member>
-        Setting the <envar>PGDATESTYLE</envar> 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 <envar>PGDATESTYLE</envar> environment
+        variable.  (This will be overridden by any of the other methods.)
        </member>
        <member>
         Running postmaster using the option <option>-o -e</option> to
-        set dates to the <literal>European</literal> convention.
+        select the <literal>European</literal> conventions.
+        (This overrides environment variables and configuration-file
+        entries.)
+       </member>
+       <member>
+        Setting the client's <envar>PGDATESTYLE</envar> 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 <command>SET</>.
        </member>
        </simplelist>
       </para>
 
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>NAMES</term>
+     <listitem>
       <para>
-       <command>SET DATESTYLE</command> 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 <function>to_char</function> family of
-       functions.
+       <command>SET NAMES</> is an alias for <command>SET CLIENT_ENCODING</>.
       </para>
      </listitem>
     </varlistentry>
@@ -199,23 +260,22 @@ SET TIME ZONE { '<replaceable class="PARAMETER">timezone</replaceable>' | LOCAL
            The value for the seed to be used by the
            <function>random</function> function. Allowed
            values are floating-point numbers between 0 and 1, which
-           are then multiplied by 2<superscript>31</>-1. This product will
-           silently overflow if a number outside the range is used.
-          </para>
-
-          <para>
-           The seed can also be set by invoking the
-           <function>setseed</function> SQL function:
-
-           <programlisting>
-SELECT setseed(<replaceable>value</replaceable>);
-           </programlisting>
+           are then multiplied by 2<superscript>31</>-1.
           </para>
          </listitem>
         </varlistentry>
        </variablelist>
        </para>
 
+       <para>
+        The seed can also be set by invoking the
+        <function>setseed</function> SQL function:
+
+        <programlisting>
+SELECT setseed(<replaceable>value</replaceable>);
+        </programlisting>
+       </para>
+
       </listitem>
      </varlistentry>
 
@@ -223,13 +283,9 @@ SELECT setseed(<replaceable>value</replaceable>);
       <term>SERVER_ENCODING</term>
       <listitem>
        <para>
-       Sets the multibyte server encoding.
-       </para>
-
-       <para>
-       This option is only available if
-       <productname>PostgreSQL</productname> 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.)
        </para>
       </listitem>
      </varlistentry>
@@ -241,18 +297,18 @@ SELECT setseed(<replaceable>value</replaceable>);
       <para>
        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.
       </para>
 
        <para>
-       The possible values for time zone depends on your operating
+       The available time zone names depend on your operating
        system. For example, on Linux
        <filename>/usr/share/zoneinfo</filename> contains the database
        of time zones.
        </para>
        <para>
-       Here are some valid values for time zone:
+       Here are some typical values for time zone names:
 
        <variablelist>
         <varlistentry>
@@ -279,6 +335,14 @@ SELECT setseed(<replaceable>value</replaceable>);
           </para>
          </listitem>
         </varlistentry>
+       </variablelist>
+       </para>
+
+       <para>
+       In addition to time zone names, <productname>PostgreSQL</productname>
+       accepts these other methods of specifying a time zone:
+
+       <variablelist>
         <varlistentry>
          <term>7</term>
          <listitem>
@@ -310,7 +374,7 @@ SELECT setseed(<replaceable>value</replaceable>);
        </variablelist>
        </para>
        <para>
-       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).
        </para>
        <para>
@@ -325,13 +389,8 @@ SELECT setseed(<replaceable>value</replaceable>);
    </para>
 
   <para>
-   An extended list of other run-time parameters can be found in the
-   <citetitle>Administrator's Guide</citetitle>.
-  </para>
-
-  <para>
    Use <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title"> to show the
-   current setting of a parameters.
+   current setting of a parameter.
   </para>
   
  </refsect1>
@@ -363,7 +422,7 @@ SELECT setseed(<replaceable>value</replaceable>);
      <term><computeroutput>ERROR:  permission denied</computeroutput></term>
      <listitem>
       <para>
-       You must be a superuser to have access to certain settings.
+       You must be a superuser to alter certain settings.
       </para>
      </listitem>
     </varlistentry>
@@ -394,7 +453,7 @@ SET DATESTYLE TO PostgreSQL,European;
 
   <para>
    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 <literal>PostgreSQL</literal> for this
    example): 
 
@@ -437,8 +496,8 @@ SELECT CURRENT_TIMESTAMP AS today;
     only numeric time zone offsets while
     <productname>PostgreSQL</productname> allows full time zone
     specifier strings as well. All other <literal>SET</literal>
-    features are a 
-    <productname>PostgreSQL</productname> extension.
+    features are
+    <productname>PostgreSQL</productname> extensions.
    </para>
   </refsect2>
  </refsect1>
index 7cd0d7d..dfb2035 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.5 2002/05/06 19:47:30 tgl Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/set_session_auth.sgml,v 1.6 2002/05/17 01:19:16 tgl Exp $ -->
 <refentry id="SQL-SET-SESSION-AUTHORIZATION">
  <docinfo>
   <date>2001-04-21</date>
@@ -16,8 +16,8 @@
 
  <refsynopsisdiv>
 <synopsis>
-SET SESSION AUTHORIZATION <parameter>username</parameter>
-SET SESSION AUTHORIZATION DEFAULT
+SET [ SESSION | LOCAL ] SESSION AUTHORIZATION <parameter>username</parameter>
+SET [ SESSION | LOCAL ] SESSION AUTHORIZATION DEFAULT
 RESET SESSION AUTHORIZATION
 </synopsis>
  </refsynopsisdiv>
@@ -52,6 +52,12 @@ RESET SESSION AUTHORIZATION
   </para>
 
   <para>
+   The <option>SESSION</> and <option>LOCAL</> modifiers act the same
+   as for the regular <xref linkend="SQL-SET" endterm="SQL-SET-title">
+   command.
+  </para>
+
+  <para>
    The <literal>DEFAULT</> and <literal>RESET</> forms reset the session
    and current user identifiers to be the originally authenticated user
    name.  These forms are always accepted.
index 37e7e85..b752f86 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.16 2002/03/06 06:48:05 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.17 2002/05/17 01:19:16 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -54,7 +54,7 @@ SHOW ALL
   <para>
    <command>SHOW</command> will display the current setting of a
    run-time parameter. These variables can be set using the
-   <command>SET</command> statement or are determined at server start.
+   <command>SET</command> statement or are determined at session start.
   </para>
  </refsect1>
 
@@ -72,25 +72,6 @@ SHOW ALL
        </para>
       </listitem>
      </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>ERROR:  permission denied</computeroutput></term>
-      <listitem>
-       <para>
-        You must be a superuser to be allowed to see certain settings.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><computeroutput>WARNING:  Time zone is unknown</computeroutput></term>
-      <listitem>
-       <para>
-       If the <envar>TZ</envar> or <envar>PGTZ</envar> environment
-       variable is not set.
-       </para>
-      </listitem>
-     </varlistentry>
     </variablelist>
    </para>
  </refsect1>
index 72157ff..889f220 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.134 2002/05/03 04:11:07 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.135 2002/05/17 01:19:16 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,9 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <literallayout><![CDATA[
+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)
 ]]></literallayout>
 
  </sect1>
index 70131be..78d6dec 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.115 2002/05/09 13:30:24 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.116 2002/05/17 01:19:16 tgl Exp $
 -->
 
 <Chapter Id="runtime">
@@ -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'
 </programlisting>
     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 (<quote>#</quote>) introduce comments
-    anywhere.
+    anywhere.  Parameter values that are not simple identifiers or
+    numbers should be single-quoted.
    </para>
 
    <para>
@@ -526,7 +528,7 @@ postmaster -c log_connections=yes -c syslog=2
 <programlisting>
 env PGOPTIONS='-c geqo=off' psql
 </programlisting>
-    (This works for any client application, not just
+    (This works for any libpq-based client application, not just
     <application>psql</application>.) 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
 =&gt; <userinput>SET ENABLE_SEQSCAN TO OFF;</userinput>
 </screen>
     See the SQL command language reference for details on the syntax.
+   </para>
+
+   <para>
     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 <literal>ALTER DATABASE</literal> and <literal>ALTER
-    USER</literal>, respectively, are used to configure these.
+    USER</literal>, 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.
    </para>
 
    <sect2 id="runtime-config-optimizer">
@@ -1092,6 +1100,34 @@ env PGOPTIONS='-c geqo=off' psql
      </varlistentry>
 
      <varlistentry>
+      <term><varname>CLIENT_ENCODING</varname> (<type>string</type>)</term>
+      <indexterm><primary>character set encoding</></>
+      <listitem>
+       <para>
+        Sets the client-side encoding for multibyte character sets.
+       The default is to use the database encoding.
+       </para>
+       <para>
+        This option is only available if
+        <productname>PostgreSQL</productname> was built with multibyte
+        support.
+      </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term><varname>DATESTYLE</varname> (<type>string</type>)</term>
+      <indexterm><primary>date style</></>
+      <listitem>
+       <para>
+        Sets the display format for dates, as well as the rules for
+       interpreting ambiguous input dates.
+        The default is <literal>ISO, US</>.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <indexterm>
        <primary>deadlock</primary>
        <secondary>timeout</secondary>
@@ -1587,6 +1623,18 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
      </varlistentry>
 
      <varlistentry>
+      <term><varname>TIMEZONE</varname> (<type>string</type>)</term>
+      <indexterm><primary>time zone</></>
+      <listitem>
+       <para>
+        Sets the time zone for displaying and interpreting timestamps.
+       The default is to use whatever the system environment
+       specifies as the timezone.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><varname>TRANSFORM_NULL_EQUALS</varname> (<type>boolean</type>)</term>
       <indexterm><primary>IS NULL</></>
       <listitem>
index ca66b0a..d6176ec 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 eca4a5d..77ad566 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 51f432b..1a13786 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 9e5002e..92c9306 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 41f1227..bb53ad8 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 405a7ce..5398d71 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 de42538..03d7a66 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 thomas@fourpalms.org",
-                                        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 9c79e7b..227fcc3 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 a3751d3..909847d 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 cf20324..1f0d175 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 bd3a7a0..0009b9d 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 <node>   stmt, schema_stmt,
@@ -246,6 +247,8 @@ static void doNegateFloat(Value *v);
 
 %type <istmt>  insert_rest
 
+%type <vsetstmt>       set_rest
+
 %type <node>   OptTableElement, ConstraintElem
 %type <node>   columnDef
 %type <defelt> 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 a3a8f25..1513f13 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 eaf626a..53bf45d 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 9a9c062..e72d8df 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 1a908d9..d6e0358 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 c5c8d31..ba962ac 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 <locale.h>
 
+#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 78cb630..88528b9 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 <ctype.h> 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 572e21b..a1813b6 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 4cc9d39..fd3f191 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 95974c6..817c87c 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 fe6cf89..2f50b4b 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 f917af9..f1d4e8e 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 <peter_e@gmx.net>.
@@ -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 843ad5c..3fae561 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 9252a8d..92e74b8 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 545b1a1..8fe62ac 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 f4f12c9..bdca5c8 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 09e1c0f..2e5fc76 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 0c5672d..a0bf47d 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 a889bd6..46d8753 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 6e0d580..cc3ebd9 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 a6eb17f..ce1b10b 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 b5056e6..a1ba131 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 <locale.h>
 
-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 21f6c60..96b85c7 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