In the continuing saga of FE/BE protocol revisions, add reporting of
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Apr 2003 19:45:10 +0000 (19:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Apr 2003 19:45:10 +0000 (19:45 +0000)
initial values and runtime changes in selected parameters.  This gets
rid of the need for an initial 'select pg_client_encoding()' query in
libpq, bringing us back to one message transmitted in each direction
for a standard connection startup.  To allow server version to be sent
using the same GUC mechanism that handles other parameters, invent the
concept of a never-settable GUC parameter: you can 'show server_version'
but it's not settable by any GUC input source.  Create 'lc_collate' and
'lc_ctype' never-settable parameters so that people can find out these
settings without need for pg_controldata.  (These side ideas were all
discussed some time ago in pgsql-hackers, but not yet implemented.)

13 files changed:
doc/src/sgml/protocol.sgml
doc/src/sgml/ref/set.sgml
doc/src/sgml/ref/show.sgml
src/backend/access/transam/xlog.c
src/backend/commands/variable.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/include/commands/variable.h
src/include/libpq/pqcomm.h
src/include/utils/guc.h
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/libpq-int.h

index 7b5f9593a985fbb4517c91488dff3e546423f418..70c255f00ce5930bcc3917e3a27b78d7840c4afc 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.30 2003/04/24 21:16:42 tgl Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.31 2003/04/25 19:45:08 tgl Exp $ -->
 
 <chapter id="protocol">
  <title>Frontend/Backend Protocol</title>
     is being started, and the frontend is just an interested bystander.
     It is still possible for the startup attempt
     to fail (ErrorResponse), but in the normal case the backend will send
-    BackendKeyData, some ParameterStatus messages, and finally ReadyForQuery.
+    some ParameterStatus messages, BackendKeyData, and finally ReadyForQuery.
    </para>
 
    <para>
    <para>
     At present there is a hard-wired set of parameters for which
     ParameterStatus will be generated: they are
-    <literal>version</> (backend version,
-    a pseudo-parameter that cannot change after startup); 
-    <literal>database_encoding</> (also not presently changeable after start);
+    <literal>server_version</> (a pseudo-parameter that cannot change after
+    startup);
+    <literal>server_encoding</> (also not presently changeable after start);
     <literal>client_encoding</>, and
     <literal>DateStyle</>.
     This set might change in the future, or even become configurable.
@@ -3881,6 +3881,13 @@ The CopyInResponse and CopyOutResponse messages carry a field indicating
 whether the COPY operation is text or binary.
 </para>
 
+<para>
+The backend sends ParameterStatus ('<literal>S</>') messages during connection
+startup for all parameters it considers interesting to the client library.
+Subsequently, a ParameterStatus message is sent whenever the active value
+changes for any of these parameters.
+</para>
+
 <para>
 The CursorResponse ('<literal>P</>') message is no longer generated by
 the backend.
index 23b77dff5c5a723d813967afa0607d436c1769af..75dc366c3f945085637d44a56576571ab984c9ec 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.73 2003/03/25 16:15:44 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.74 2003/04/25 19:45:08 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -52,7 +52,7 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
       <term><replaceable class="PARAMETER">variable</replaceable></term>
       <listitem>
        <para>
-        A settable run-time parameter.
+        Name of a settable run-time parameter.
        </para>
       </listitem>
      </varlistentry>
@@ -79,8 +79,9 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
 
   <para>
    The <command>SET</command> command changes run-time configuration
-   parameters.  Many of the run-time parameters listed in the
-   <xref linkend="runtime-config"> can be changed on-the-fly with <command>SET</command>.
+   parameters.  Many of the run-time parameters listed in
+   <xref linkend="runtime-config"> 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
@@ -123,7 +124,7 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
      <listitem>
       <para>
        Choose the date/time representation style. Two separate
-       settings are involved: the default date/time output and the
+       settings are involved: the default date/time output format and the
        interpretation of ambiguous input.
       </para>
 
@@ -147,7 +148,7 @@ SET [ SESSION | LOCAL ] TIME ZONE { <replaceable class="PARAMETER">timezone</rep
           <para>
            Use Oracle/Ingres-style dates and times. Note that this
            style has nothing to do with SQL (which mandates ISO 8601
-           style), the naming of this option is a historical accident.
+           style); the naming of this option is a historical accident.
           </para>
          </listitem>
         </varlistentry>
@@ -283,17 +284,6 @@ SELECT setseed(<replaceable>value</replaceable>);
      </listitem>
     </varlistentry>
 
-    <varlistentry>
-     <term>SERVER_ENCODING</term>
-     <listitem>
-      <para>
-       Shows the server-side multibyte encoding.  (At present, this
-       parameter can be shown but not set, because the encoding is
-       determined at <application>initdb</> time.)
-      </para>
-     </listitem>
-    </varlistentry>
-
     <varlistentry>
      <term>TIME ZONE</term>
      <term>TIMEZONE</term>
@@ -410,7 +400,7 @@ SELECT setseed(<replaceable>value</replaceable>);
     </varlistentry>
      
     <varlistentry>
-     <term><computeroutput>ERROR:  '<replaceable>name</replaceable> is not a
+     <term><computeroutput>ERROR:  '<replaceable>name</replaceable>' is not a
     valid option name</computeroutput></term>
      <listitem>
       <para>
@@ -447,7 +437,7 @@ SELECT setseed(<replaceable>value</replaceable>);
   <title>Notes</title>
 
   <para>
-   The function <function>set_config</function> provides the equivalent
+   The function <function>set_config</function> provides equivalent
    capability. See <xref linkend="functions-misc">.
   </para>
  </refsect1>
@@ -517,6 +507,8 @@ SELECT CURRENT_TIMESTAMP AS today;
   <title>See Also</title>
 
   <simpara>
+   <xref linkend="SQL-SHOW" endterm="SQL-SHOW-title">,
+   <xref linkend="SQL-RESET" endterm="SQL-RESET-title">,
    <xref linkend="sql-set-constraints" endterm="sql-set-constraints-title">,
    <xref linkend="sql-set-session-authorization" endterm="sql-set-session-authorization-title">,
    <xref linkend="sql-set-transaction" endterm="sql-set-transaction-title">
index 832c4392cbf27d003baa4614b1d0cd1e7d4d5f68..0fec5fcce557cefc003d236d62a450ca0dabe198 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.24 2003/03/25 16:15:44 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/show.sgml,v 1.25 2003/04/25 19:45:08 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -52,12 +52,13 @@ SHOW ALL
  <refsect1 id="R1-SQL-SHOW-1">
   <title>Description</title>
   <para>
-   <command>SHOW</command> will display the current setting of a
-   run-time parameter. These variables can be set using the
+   <command>SHOW</command> will display the current setting of
+   run-time parameters. These variables can be set using the
    <command>SET</command> statement, by editing the
-   <filename>postgresql.conf</filename>, through the
-   <envar>PGOPTIONS</envar> environmental variable, or through a
-   command-line flag when starting the
+   <filename>postgresql.conf</filename> configuration file, through the
+   <envar>PGOPTIONS</envar> environmental variable (when using libpq
+   or a libpq-based application), or through
+   command-line flags when starting the
    <application>postmaster</application>.
   </para>
 
@@ -66,6 +67,64 @@ SHOW ALL
    does not start a new transaction block. See the
    <varname>autocommit</> section in <xref linkend="runtime-config"> for details.
   </para>
+
+  <para>
+   Available parameters are documented in
+   <xref linkend="runtime-config"> and on the
+   <xref linkend="SQL-SET" endterm="SQL-SET-title"> reference page.
+   In addition, there are a few parameters that can be shown but not set:
+
+   <variablelist>
+
+    <varlistentry>
+     <term>SERVER_VERSION</term>
+     <listitem>
+      <para>
+       Shows the server's version number.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>SERVER_ENCODING</term>
+     <listitem>
+      <para>
+       Shows the server-side multibyte encoding.  At present, this
+       parameter can be shown but not set, because the encoding is
+       determined at database creation time.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>LC_COLLATE</term>
+     <listitem>
+      <para>
+       Shows the database's locale setting for collation (text ordering).
+       At present, this parameter can be shown but not set, because the
+       setting is determined at <application>initdb</> time.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term>LC_CTYPE</term>
+     <listitem>
+      <para>
+       Shows the database's locale setting for character set considerations.
+       At present, this parameter can be shown but not set, because the
+       setting is determined at <application>initdb</> time.
+      </para>
+     </listitem>
+    </varlistentry>
+
+   </variablelist>
+  </para>
+
+  <para>
+   Use <xref linkend="SQL-SET" endterm="SQL-SET-title"> to set the value
+   of settable parameters.
+  </para>
  </refsect1>
 
  <refsect1>
@@ -79,7 +138,7 @@ SHOW ALL
       <listitem>
        <para>
    Message returned if <replaceable>name</replaceable> does
-   not stand for an existing parameter.
+   not stand for a known parameter.
        </para>
       </listitem>
      </varlistentry>
index 4030a11a52e5f265cccfd699de44fcac336dfba3..d1523dc89b038177f0e718d5cd7a1b6adea5658a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, 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.113 2003/04/18 01:03:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.114 2003/04/25 19:45:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,7 @@
 #include "storage/sinval.h"
 #include "storage/spin.h"
 #include "utils/builtins.h"
+#include "utils/guc.h"
 #include "utils/relcache.h"
 #include "miscadmin.h"
 
@@ -2260,6 +2261,12 @@ ReadControlFile(void)
             "\twhich is not recognized by setlocale().\n"
             "\tIt looks like you need to initdb.",
             ControlFile->lc_ctype);
+
+   /* Make the fixed locale settings visible as GUC variables, too */
+   SetConfigOption("lc_collate", ControlFile->lc_collate,
+                   PGC_INTERNAL, PGC_S_OVERRIDE);
+   SetConfigOption("lc_ctype", ControlFile->lc_ctype,
+                   PGC_INTERNAL, PGC_S_OVERRIDE);
 }
 
 void
index 6ce1487e86ef4c32feb2319dfd4c40da79a9f99b..7b23cc80d0094180bad0b00d8fb7ba675cc55d3b 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.73 2003/02/01 18:31:28 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.74 2003/04/25 19:45:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -500,22 +500,6 @@ assign_client_encoding(const char *value, bool doit, bool interactive)
 }
 
 
-const char *
-assign_server_encoding(const char *value, bool doit, bool interactive)
-{
-   if (interactive)
-       elog(ERROR, "SET SERVER_ENCODING is not supported");
-   /* Pretend never to fail in noninteractive case */
-   return value;
-}
-
-const char *
-show_server_encoding(void)
-{
-   return GetDatabaseEncodingName();
-}
-
-
 /*
  * SET SESSION AUTHORIZATION
  *
index 36dd3c7b5c2c3fa1f6e7acbe54740c48b7b09773..4d76e69ac995961f3fa413f77fe01b2334cd96a1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.119 2003/02/19 14:31:26 ishii Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.120 2003/04/25 19:45:08 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -128,6 +128,9 @@ ReverifyMyDatabase(const char *name)
     * info out of the pg_database tuple.
     */
    SetDatabaseEncoding(dbform->encoding);
+   /* Record it as a GUC internal option, too */
+   SetConfigOption("server_encoding", GetDatabaseEncodingName(),
+                   PGC_INTERNAL, PGC_S_OVERRIDE);
    /* If we have no other source of client_encoding, use server encoding */
    SetConfigOption("client_encoding", GetDatabaseEncodingName(),
                    PGC_BACKEND, PGC_S_DEFAULT);
@@ -400,6 +403,12 @@ InitPostgres(const char *dbname, const char *username)
    /* initialize client encoding */
    InitializeClientEncoding();
 
+   /*
+    * Now all default states are fully set up.  Report them to client
+    * if appropriate.
+    */
+   BeginReportingGUCOptions();
+
    /*
     * Set up process-exit callback to do pre-shutdown cleanup.  This
     * should be last because we want shmem_exit to call this routine
index 89b625277971b3c660d327864d20ccb92f807aa1..f18c74c472afe5429bebade24efe3034d78c05c8 100644 (file)
@@ -5,10 +5,13 @@
  * 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.118 2003/03/28 20:17:13 tgl Exp $
  *
- * Copyright 2000 by PostgreSQL Global Development Group
+ * Copyright 2000-2003 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.119 2003/04/25 19:45:09 tgl Exp $
+ *
  *--------------------------------------------------------------------
  */
 
@@ -32,6 +35,7 @@
 #include "funcapi.h"
 #include "libpq/auth.h"
 #include "libpq/pqcomm.h"
+#include "libpq/pqformat.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "optimizer/cost.h"
 #include "pgstat.h"
 
 
-/* XXX these should be in other modules' header files */
+#ifndef PG_KRB_SRVTAB
+#define PG_KRB_SRVTAB ""
+#endif
+
+
+/* XXX these should appear in other modules' header files */
 extern bool Log_connections;
 extern int PreAuthDelay;
 extern int AuthenticationTimeout;
@@ -70,9 +79,18 @@ static const char *assign_facility(const char *facility,
                bool doit, bool interactive);
 #endif
 
+static const char *assign_defaultxactisolevel(const char *newval,
+                          bool doit, bool interactive);
+static const char *assign_log_min_messages(const char *newval,
+                          bool doit, bool interactive);
+static const char *assign_client_min_messages(const char *newval,
+                          bool doit, bool interactive);
+static const char *assign_min_error_statement(const char *newval, bool doit,
+                          bool interactive);
 static const char *assign_msglvl(int *var, const char *newval,
              bool doit, bool interactive);
 
+
 /*
  * Debugging options
  */
@@ -85,6 +103,7 @@ bool     Debug_print_plan = false;
 bool       Debug_print_parse = false;
 bool       Debug_print_rewritten = false;
 bool       Debug_pretty_print = false;
+bool       Explain_pretty_print = true;
 
 bool       log_parser_stats = false;
 bool       log_planner_stats = false;
@@ -93,8 +112,6 @@ bool     log_statement_stats = false;        /* this is sort of all
                                                 * three above together */
 bool       log_btree_build_stats = false;
 
-bool       Explain_pretty_print = true;
-
 bool       SQL_inheritance = true;
 
 bool       Australian_timezones = false;
@@ -102,40 +119,31 @@ bool      Australian_timezones = false;
 bool       Password_encryption = true;
 
 int            log_min_error_statement = PANIC;
-char      *log_min_error_statement_str = NULL;
-const char log_min_error_statement_str_default[] = "panic";
-
 int            log_min_messages = NOTICE;
-char      *log_min_messages_str = NULL;
-const char log_min_messages_str_default[] = "notice";
-
 int            client_min_messages = NOTICE;
-char      *client_min_messages_str = NULL;
-const char client_min_messages_str_default[] = "notice";
 
 
-#ifndef PG_KRB_SRVTAB
-#define PG_KRB_SRVTAB ""
-#endif
-
 /*
  * 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 char *log_min_error_statement_str;
+static char *log_min_messages_str;
+static char *client_min_messages_str;
 static double phony_random_seed;
 static char *client_encoding_string;
 static char *datestyle_string;
 static char *default_iso_level_string;
+static char *locale_collate;
+static char *locale_ctype;
 static char *regex_flavor_string;
 static char *server_encoding_string;
+static char *server_version_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
@@ -171,6 +179,7 @@ struct config_generic
 #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 */
+#define GUC_REPORT         0x0010      /* auto-report changes to client */
 
 /* bit values in status field */
 #define GUC_HAVE_TENTATIVE 0x0001      /* tentative value is defined */
@@ -763,22 +772,24 @@ static struct config_string
            ConfigureNamesString[] =
 {
    {
-       {"client_encoding", PGC_USERSET}, &client_encoding_string,
+       {"client_encoding", PGC_USERSET, GUC_REPORT},
+       &client_encoding_string,
        "SQL_ASCII", assign_client_encoding, NULL
    },
 
    {
        {"client_min_messages", PGC_USERSET}, &client_min_messages_str,
-       client_min_messages_str_default, assign_client_min_messages, NULL
+       "notice", assign_client_min_messages, NULL
    },
 
    {
        {"log_min_error_statement", PGC_USERSET}, &log_min_error_statement_str,
-       log_min_error_statement_str_default, assign_min_error_statement, NULL
+       "panic", assign_min_error_statement, NULL
    },
 
    {
-       {"DateStyle", PGC_USERSET, GUC_LIST_INPUT}, &datestyle_string,
+       {"DateStyle", PGC_USERSET, GUC_LIST_INPUT | GUC_REPORT},
+       &datestyle_string,
        "ISO, US", assign_datestyle, show_datestyle
    },
 
@@ -799,6 +810,16 @@ static struct config_string
 
    /* See main.c about why defaults for LC_foo are not all alike */
 
+   {
+       {"lc_collate", PGC_INTERNAL}, &locale_collate,
+       "C", NULL, NULL
+   },
+
+   {
+       {"lc_ctype", PGC_INTERNAL}, &locale_ctype,
+       "C", NULL, NULL
+   },
+
    {
        {"lc_messages", PGC_SUSET}, &locale_messages,
        "", locale_messages_assign, NULL
@@ -837,13 +858,20 @@ static struct config_string
    },
 
    {
-       {"server_encoding", PGC_USERSET}, &server_encoding_string,
-       "SQL_ASCII", assign_server_encoding, show_server_encoding
+       {"server_encoding", PGC_INTERNAL, GUC_REPORT},
+       &server_encoding_string,
+       "SQL_ASCII", NULL, NULL
+   },
+
+   {
+       {"server_version", PGC_INTERNAL, GUC_REPORT},
+       &server_version_string,
+       PG_VERSION, NULL, NULL
    },
 
    {
        {"log_min_messages", PGC_USERSET}, &log_min_messages_str,
-       log_min_messages_str_default, assign_log_min_messages, NULL
+       "notice", assign_log_min_messages, NULL
    },
 
    {
@@ -910,10 +938,13 @@ static int    num_guc_variables;
 
 static bool guc_dirty;         /* TRUE if need to do commit/abort work */
 
+static bool reporting_enabled; /* TRUE to enable GUC_REPORT */
+
 static char *guc_string_workspace;     /* for avoiding memory leaks */
 
 
 static int guc_var_compare(const void *a, const void *b);
+static void ReportGUCOption(struct config_generic *record);
 static char *_ShowOption(struct config_generic * record);
 
 
@@ -1182,6 +1213,8 @@ InitializeGUCOptions(void)
 
    guc_dirty = false;
 
+   reporting_enabled = false;
+
    guc_string_workspace = NULL;
 
    /*
@@ -1325,6 +1358,9 @@ ResetAllOptions(void)
                    break;
                }
        }
+
+       if (gconf->flags & GUC_REPORT)
+           ReportGUCOption(gconf);
    }
 }
 
@@ -1351,11 +1387,14 @@ AtEOXact_GUC(bool isCommit)
    for (i = 0; i < num_guc_variables; i++)
    {
        struct config_generic *gconf = guc_variables[i];
+       bool    changed;
 
        /* Skip if nothing's happened to this var in this transaction */
        if (gconf->status == 0)
            continue;
 
+       changed = false;
+
        switch (gconf->vartype)
        {
            case PGC_BOOL:
@@ -1375,6 +1414,7 @@ AtEOXact_GUC(bool isCommit)
                                                       true, false))
                                elog(LOG, "Failed to commit %s", conf->gen.name);
                        *conf->variable = conf->session_val;
+                       changed = true;
                    }
                    conf->gen.source = conf->gen.session_source;
                    conf->gen.status = 0;
@@ -1397,6 +1437,7 @@ AtEOXact_GUC(bool isCommit)
                                                       true, false))
                                elog(LOG, "Failed to commit %s", conf->gen.name);
                        *conf->variable = conf->session_val;
+                       changed = true;
                    }
                    conf->gen.source = conf->gen.session_source;
                    conf->gen.status = 0;
@@ -1419,6 +1460,7 @@ AtEOXact_GUC(bool isCommit)
                                                       true, false))
                                elog(LOG, "Failed to commit %s", conf->gen.name);
                        *conf->variable = conf->session_val;
+                       changed = true;
                    }
                    conf->gen.source = conf->gen.session_source;
                    conf->gen.status = 0;
@@ -1460,18 +1502,72 @@ AtEOXact_GUC(bool isCommit)
                        }
 
                        SET_STRING_VARIABLE(conf, str);
+                       changed = true;
                    }
                    conf->gen.source = conf->gen.session_source;
                    conf->gen.status = 0;
                    break;
                }
        }
+
+       if (changed && (gconf->flags & GUC_REPORT))
+           ReportGUCOption(gconf);
    }
 
    guc_dirty = false;
 }
 
 
+/*
+ * Start up automatic reporting of changes to variables marked GUC_REPORT.
+ * This is executed at completion of backend startup.
+ */
+void
+BeginReportingGUCOptions(void)
+{
+   int         i;
+
+   /*
+    * Don't do anything unless talking to an interactive frontend of
+    * protocol 3.0 or later.
+    */
+   if (whereToSendOutput != Remote ||
+       PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
+       return;
+
+   reporting_enabled = true;
+
+   /* Transmit initial values of interesting variables */
+   for (i = 0; i < num_guc_variables; i++)
+   {
+       struct config_generic *conf = guc_variables[i];
+
+       if (conf->flags & GUC_REPORT)
+           ReportGUCOption(conf);
+   }
+}
+
+/*
+ * ReportGUCOption: if appropriate, transmit option value to frontend
+ */
+static void
+ReportGUCOption(struct config_generic *record)
+{
+   if (reporting_enabled && (record->flags & GUC_REPORT))
+   {
+       char    *val = _ShowOption(record);
+       StringInfoData msgbuf;
+
+       pq_beginmessage(&msgbuf, 'S');
+       pq_sendstring(&msgbuf, record->name);
+       pq_sendstring(&msgbuf, val);
+       pq_endmessage(&msgbuf);
+
+       pfree(val);
+   }
+}
+
+
 /*
  * Try to interpret value as boolean value.  Valid values are: true,
  * false, yes, no, on, off, 1, 0.  If the string parses okay, return
@@ -1638,6 +1734,16 @@ set_config_option(const char *name, const char *value,
     */
    switch (record->context)
    {
+       case PGC_INTERNAL:
+           if (context == PGC_SIGHUP)
+               return true;
+           if (context != PGC_INTERNAL)
+           {
+               elog(elevel, "'%s' cannot be changed",
+                    name);
+               return false;
+           }
+           break;
        case PGC_POSTMASTER:
            if (context == PGC_SIGHUP)
                return true;
@@ -2054,6 +2160,9 @@ set_config_option(const char *name, const char *value,
            }
    }
 
+   if (DoIt && (record->flags & GUC_REPORT))
+           ReportGUCOption(record);
+
    return true;
 }
 
@@ -2614,8 +2723,10 @@ show_all_settings(PG_FUNCTION_ARGS)
        SRF_RETURN_NEXT(funcctx, result);
    }
    else
-/* do when there is no more left */
+   {
+       /* do when there is no more left */
        SRF_RETURN_DONE(funcctx);
+   }
 }
 
 static char *
@@ -2736,52 +2847,6 @@ ParseLongOption(const char *string, char **name, char **value)
 }
 
 
-
-#ifdef HAVE_SYSLOG
-
-static const char *
-assign_facility(const char *facility, bool doit, bool interactive)
-{
-   if (strcasecmp(facility, "LOCAL0") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL1") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL2") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL3") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL4") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL5") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL6") == 0)
-       return facility;
-   if (strcasecmp(facility, "LOCAL7") == 0)
-       return facility;
-   return NULL;
-}
-#endif
-
-
-static const char *
-assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
-{
-   if (strcasecmp(newval, "serializable") == 0)
-   {
-       if (doit)
-           DefaultXactIsoLevel = XACT_SERIALIZABLE;
-   }
-   else if (strcasecmp(newval, "read committed") == 0)
-   {
-       if (doit)
-           DefaultXactIsoLevel = XACT_READ_COMMITTED;
-   }
-   else
-       return NULL;
-   return newval;
-}
-
-
 /*
  * Handle options fetched from pg_database.datconfig or pg_shadow.useconfig.
  * The array parameter must be an array of TEXT (it must not be NULL).
@@ -2993,21 +3058,70 @@ GUCArrayDelete(ArrayType *array, const char *name)
    return newarray;
 }
 
-const char *
+
+/*
+ * assign_hook subroutines
+ */
+
+#ifdef HAVE_SYSLOG
+
+static const char *
+assign_facility(const char *facility, bool doit, bool interactive)
+{
+   if (strcasecmp(facility, "LOCAL0") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL1") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL2") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL3") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL4") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL5") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL6") == 0)
+       return facility;
+   if (strcasecmp(facility, "LOCAL7") == 0)
+       return facility;
+   return NULL;
+}
+#endif
+
+
+static const char *
+assign_defaultxactisolevel(const char *newval, bool doit, bool interactive)
+{
+   if (strcasecmp(newval, "serializable") == 0)
+   {
+       if (doit)
+           DefaultXactIsoLevel = XACT_SERIALIZABLE;
+   }
+   else if (strcasecmp(newval, "read committed") == 0)
+   {
+       if (doit)
+           DefaultXactIsoLevel = XACT_READ_COMMITTED;
+   }
+   else
+       return NULL;
+   return newval;
+}
+
+static const char *
 assign_log_min_messages(const char *newval,
                           bool doit, bool interactive)
 {
    return (assign_msglvl(&log_min_messages, newval, doit, interactive));
 }
 
-const char *
+static const char *
 assign_client_min_messages(const char *newval,
                           bool doit, bool interactive)
 {
    return (assign_msglvl(&client_min_messages, newval, doit, interactive));
 }
 
-const char *
+static const char *
 assign_min_error_statement(const char *newval, bool doit, bool interactive)
 {
    return (assign_msglvl(&log_min_error_statement, newval, doit, interactive));
@@ -3087,4 +3201,5 @@ assign_msglvl(int *var, const char *newval, bool doit, bool interactive)
    return newval;              /* OK */
 }
 
+
 #include "guc-file.c"
index 73687178fe8439cd27295f3bdfa670df60cd6b3e..68a0ebf7450e15a568fbf659e076ca42547e6d4a 100644 (file)
@@ -2,7 +2,7 @@
  * variable.h
  *     Routines for handling specialized SET variables.
  *
- * $Id: variable.h,v 1.19 2002/09/04 20:31:42 momjian Exp $
+ * $Id: variable.h,v 1.20 2003/04/25 19:45:09 tgl Exp $
  *
  */
 #ifndef VARIABLE_H
@@ -22,9 +22,6 @@ extern bool assign_random_seed(double value,
 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);
index 4f458c51c29a5312fa5c3eb47186a550d733de8b..6a871c7c6f61ec427a0f327edc66b5f66586d8c1 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqcomm.h,v 1.79 2003/04/24 21:16:44 tgl Exp $
+ * $Id: pqcomm.h,v 1.80 2003/04/25 19:45:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -106,7 +106,7 @@ typedef union SockAddr
 /* The earliest and latest frontend/backend protocol version supported. */
 
 #define PG_PROTOCOL_EARLIEST   PG_PROTOCOL(1,0)
-#define PG_PROTOCOL_LATEST     PG_PROTOCOL(3,103) /* XXX temporary value */
+#define PG_PROTOCOL_LATEST     PG_PROTOCOL(3,104) /* XXX temporary value */
 
 typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
 
index f39f0a18544ad6ba35c022448a6de84d0778168d..47a5eeab18723b2eba11c00a53a91d2052671fd0 100644 (file)
@@ -1,10 +1,14 @@
-/*
+/*--------------------------------------------------------------------
  * guc.h
  *
  * External declarations pertaining to backend/utils/misc/guc.c and
  * backend/utils/misc/guc-file.l
  *
- * $Id: guc.h,v 1.26 2002/11/15 00:47:22 momjian Exp $
+ * Copyright 2000-2003 by PostgreSQL Global Development Group
+ * Written by Peter Eisentraut <peter_e@gmx.net>.
+ *
+ * $Id: guc.h,v 1.27 2003/04/25 19:45:09 tgl Exp $
+ *--------------------------------------------------------------------
  */
 #ifndef GUC_H
 #define GUC_H
  * Certain options can only be set at certain times. The rules are
  * like this:
  *
+ * INTERNAL options cannot be set by the user at all, but only through
+ * internal processes ("server_version" is an example).  These are GUC
+ * variables only so they can be shown by SHOW, etc.
+ *
  * POSTMASTER options can only be set when the postmaster starts,
  * either from the configuration file or the command line.
  *
  * SIGHUP options can only be set at postmaster startup or by changing
  * the configuration file and sending the HUP signal to the postmaster
  * or a backend process. (Notice that the signal receipt will not be
- * evaluated immediately. The postmaster and the backend block at a
+ * evaluated immediately. The postmaster and the backend check it at a
  * certain point in their main loop. It's safer to wait than to read a
  * file asynchronously.)
  *
  * BACKEND options can only be set at postmaster startup, from the
- * configuration file, or with the PGOPTIONS variable from the client
- * when the connection is initiated.  Furthermore, an already-started
- * backend will ignore changes to such an option in the configuration
- * file.  The idea is that these options are fixed for a given backend
- * once it's started, but they can vary across backends.
+ * configuration file, or by client request in the connection startup
+ * packet (e.g., from libpq's PGOPTIONS variable).  Furthermore, an
+ * already-started backend will ignore changes to such an option in the
+ * configuration file.  The idea is that these options are fixed for a
+ * given backend once it's started, but they can vary across backends.
  *
  * SUSET options can be set at postmaster startup, with the SIGHUP
  * mechanism, or from SQL if you're a superuser. These options cannot
- * be set using the PGOPTIONS mechanism, because there is not check as
- * to who does this.
+ * be set in the connection startup packet, because when it is processed
+ * we don't yet know if the user is a superuser.
  *
  * USERSET options can be set by anyone any time.
  */
 typedef enum
 {
+   PGC_INTERNAL,
    PGC_POSTMASTER,
    PGC_SIGHUP,
    PGC_BACKEND,
@@ -57,7 +66,8 @@ typedef enum
  * 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.
+ * as the current value.  Note that source == PGC_S_OVERRIDE should be
+ * used when setting a PGC_INTERNAL option.
  */
 typedef enum
 {
@@ -67,11 +77,35 @@ typedef enum
    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_CLIENT = 6,           /* from client connection request */
    PGC_S_OVERRIDE = 7,         /* special case to forcibly set default */
    PGC_S_SESSION = 8           /* SET command */
 } GucSource;
 
+
+/* GUC vars that are actually declared in guc.c, rather than elsewhere */
+extern bool log_statement;
+extern bool log_duration;
+extern bool Debug_print_plan;
+extern bool Debug_print_parse;
+extern bool Debug_print_rewritten;
+extern bool Debug_pretty_print;
+extern bool Explain_pretty_print;
+
+extern bool log_parser_stats;
+extern bool log_planner_stats;
+extern bool log_executor_stats;
+extern bool log_statement_stats;
+extern bool log_btree_build_stats;
+
+extern bool SQL_inheritance;
+extern bool Australian_timezones;
+
+extern int log_min_error_statement;
+extern int log_min_messages;
+extern int client_min_messages;
+
+
 extern void SetConfigOption(const char *name, const char *value,
                GucContext context, GucSource source);
 extern const char *GetConfigOption(const char *name);
@@ -80,6 +114,7 @@ extern void ProcessConfigFile(GucContext context);
 extern void InitializeGUCOptions(void);
 extern void ResetAllOptions(void);
 extern void AtEOXact_GUC(bool isCommit);
+extern void BeginReportingGUCOptions(void);
 extern void ParseLongOption(const char *string, char **name, char **value);
 extern bool set_config_option(const char *name, const char *value,
                  GucContext context, GucSource source,
@@ -100,42 +135,4 @@ 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);
 
-extern const char *assign_min_error_statement(const char *newval, bool doit,
-                          bool interactive);
-
-extern const char *assign_log_min_messages(const char *newval,
-                          bool doit, bool interactive);
-extern const char *assign_client_min_messages(const char *newval,
-                          bool doit, bool interactive);
-extern bool log_statement;
-extern bool log_duration;
-extern bool Debug_print_plan;
-extern bool Debug_print_parse;
-extern bool Debug_print_rewritten;
-extern bool Debug_pretty_print;
-
-extern bool log_parser_stats;
-extern bool log_planner_stats;
-extern bool log_executor_stats;
-extern bool log_statement_stats;
-extern bool log_btree_build_stats;
-
-extern bool Explain_pretty_print;
-
-extern bool SQL_inheritance;
-extern bool Australian_timezones;
-
-extern int log_min_error_statement;
-extern char *log_min_error_statement_str;
-extern const char log_min_error_statement_str_default[];
-
-extern int log_min_messages;
-extern char *log_min_messages_str;
-extern const char log_min_messages_str_default[];
-
-extern int client_min_messages;
-extern char *client_min_messages_str;
-
-extern const char client_min_messages_str_default[];
-
 #endif   /* GUC_H */
index a31f34d7a98fa8d33f32a5039c41d3dd1bed9cb9..e2df4de859a8021b8b146ad6e5f250fc7303f3e2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.236 2003/04/25 01:24:00 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.237 2003/04/25 19:45:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -174,8 +174,6 @@ static const struct EnvironmentOptions
 
 static int connectDBStart(PGconn *conn);
 static int connectDBComplete(PGconn *conn);
-static bool PQsetenvStart(PGconn *conn);
-static PostgresPollingStatusType PQsetenvPoll(PGconn *conn);
 static PGconn *makeEmptyPGconn(void);
 static void freePGconn(PGconn *conn);
 static void closePGconn(PGconn *conn);
@@ -1207,10 +1205,6 @@ PQconnectPoll(PGconn *conn)
        case CONNECTION_MADE:
            break;
 
-       case CONNECTION_SETENV:
-           /* We allow PQsetenvPoll to decide whether to proceed */
-           break;
-
        default:
            printfPQExpBuffer(&conn->errorMessage,
                              libpq_gettext(
@@ -1517,10 +1511,10 @@ keep_going:                     /* We will come back to here until there
                 * message indicates that startup is successful, but we
                 * might also get an Error message indicating failure.
                 * (Notice messages indicating nonfatal warnings are also
-                * allowed by the protocol, as is a BackendKeyData
-                * message.) Easiest way to handle this is to let
-                * PQgetResult() read the messages. We just have to fake
-                * it out about the state of the connection, by setting
+                * allowed by the protocol, as are ParameterStatus and
+                * BackendKeyData messages.) Easiest way to handle this is
+                * to let PQgetResult() read the messages. We just have to
+                * fake it out about the state of the connection, by setting
                 * asyncStatus = PGASYNC_BUSY (done above).
                 */
 
@@ -1554,44 +1548,11 @@ keep_going:                     /* We will come back to here until there
                }
 
                /*
-                * Post-connection housekeeping. Prepare to send
-                * environment variables to server.
+                * We are open for business!
                 */
-               if (!PQsetenvStart(conn))
-                   goto error_return;
-
-               conn->status = CONNECTION_SETENV;
-
-               goto keep_going;
-           }
-
-       case CONNECTION_SETENV:
-
-           /*
-            * We pretend that the connection is OK for the duration of
-            * these queries.
-            */
-           conn->status = CONNECTION_OK;
-
-           switch (PQsetenvPoll(conn))
-           {
-               case PGRES_POLLING_OK:  /* Success */
-                   conn->status = CONNECTION_OK;
-                   return PGRES_POLLING_OK;
-
-               case PGRES_POLLING_READING:     /* Still going */
-                   conn->status = CONNECTION_SETENV;
-                   return PGRES_POLLING_READING;
-
-               case PGRES_POLLING_WRITING:     /* Still going */
-                   conn->status = CONNECTION_SETENV;
-                   return PGRES_POLLING_WRITING;
-
-               default:
-                   conn->status = CONNECTION_SETENV;
-                   goto error_return;
+               conn->status = CONNECTION_OK;
+               return PGRES_POLLING_OK;
            }
-           /* Unreachable */
 
        default:
            printfPQExpBuffer(&conn->errorMessage,
@@ -1618,239 +1579,6 @@ error_return:
 }
 
 
-/*
- *     PQsetenvStart
- *
- * Starts the process of passing the values of a standard set of environment
- * variables to the backend.
- */
-static bool
-PQsetenvStart(PGconn *conn)
-{
-   if (conn == NULL ||
-       conn->status == CONNECTION_BAD ||
-       conn->setenv_state != SETENV_STATE_IDLE)
-       return false;
-
-   conn->setenv_state = SETENV_STATE_ENCODINGS_SEND;
-
-   return true;
-}
-
-/*
- *     PQsetenvPoll
- *
- * Polls the process of passing the values of a standard set of environment
- * variables to the backend.
- */
-static PostgresPollingStatusType
-PQsetenvPoll(PGconn *conn)
-{
-   PGresult   *res;
-
-   if (conn == NULL || conn->status == CONNECTION_BAD)
-       return PGRES_POLLING_FAILED;
-
-   /* Check whether there are any data for us */
-   switch (conn->setenv_state)
-   {
-           /* These are reading states */
-       case SETENV_STATE_ENCODINGS_WAIT:
-           {
-               /* Load waiting data */
-               int         n = pqReadData(conn);
-
-               if (n < 0)
-                   goto error_return;
-               if (n == 0)
-                   return PGRES_POLLING_READING;
-
-               break;
-           }
-
-           /* These are writing states, so we just proceed. */
-       case SETENV_STATE_ENCODINGS_SEND:
-           break;
-
-           /* Should we raise an error if called when not active? */
-       case SETENV_STATE_IDLE:
-           return PGRES_POLLING_OK;
-
-       default:
-           printfPQExpBuffer(&conn->errorMessage,
-                             libpq_gettext(
-                                           "invalid setenv state %c, "
-                            "probably indicative of memory corruption\n"
-                                           ),
-                             conn->setenv_state);
-           goto error_return;
-   }
-
-   /* We will loop here until there is nothing left to do in this call. */
-   for (;;)
-   {
-       switch (conn->setenv_state)
-       {
-           case SETENV_STATE_ENCODINGS_SEND:
-               {
-                   const char *env = getenv("PGCLIENTENCODING");
-
-                   if (!env || *env == '\0')
-                   {
-                       /*
-                        * PGCLIENTENCODING is not specified, so query
-                        * server for it.  We must use begin/commit in
-                        * case autocommit is off by default.
-                        */
-                       if (!PQsendQuery(conn, "begin; select pg_client_encoding(); commit"))
-                           goto error_return;
-
-                       conn->setenv_state = SETENV_STATE_ENCODINGS_WAIT;
-                       return PGRES_POLLING_READING;
-                   }
-                   else
-                   {
-                       /* otherwise set client encoding in pg_conn struct */
-                       int         encoding = pg_char_to_encoding(env);
-
-                       if (encoding < 0)
-                       {
-                           printfPQExpBuffer(&conn->errorMessage,
-                                             libpq_gettext("invalid encoding name in PGCLIENTENCODING: %s\n"),
-                                             env);
-                           goto error_return;
-                       }
-                       conn->client_encoding = encoding;
-
-                       /* Move on to setting the environment options */
-                       conn->setenv_state = SETENV_STATE_IDLE;
-                   }
-                   break;
-               }
-
-           case SETENV_STATE_ENCODINGS_WAIT:
-               {
-                   if (PQisBusy(conn))
-                       return PGRES_POLLING_READING;
-
-                   res = PQgetResult(conn);
-
-                   if (res)
-                   {
-                       if (PQresultStatus(res) == PGRES_TUPLES_OK)
-                       {
-                           /* set client encoding in pg_conn struct */
-                           char       *encoding;
-
-                           encoding = PQgetvalue(res, 0, 0);
-                           if (!encoding)      /* this should not happen */
-                               conn->client_encoding = PG_SQL_ASCII;
-                           else
-                               conn->client_encoding = pg_char_to_encoding(encoding);
-                       }
-                       else if (PQresultStatus(res) != PGRES_COMMAND_OK)
-                       {
-                           PQclear(res);
-                           goto error_return;
-                       }
-                       PQclear(res);
-                       /* Keep reading until PQgetResult returns NULL */
-                   }
-                   else
-                   {
-                       /*
-                        * NULL result indicates that the query is
-                        * finished
-                        */
-                       conn->setenv_state = SETENV_STATE_IDLE;
-                   }
-                   break;
-               }
-
-           case SETENV_STATE_IDLE:
-               return PGRES_POLLING_OK;
-
-           default:
-               printfPQExpBuffer(&conn->errorMessage,
-                                 libpq_gettext("invalid state %c, "
-                          "probably indicative of memory corruption\n"),
-                                 conn->setenv_state);
-               goto error_return;
-       }
-   }
-
-   /* Unreachable */
-
-error_return:
-   conn->setenv_state = SETENV_STATE_IDLE;
-   return PGRES_POLLING_FAILED;
-}
-
-
-#ifdef NOT_USED
-
-/*
- *     PQsetenv
- *
- * Passes the values of a standard set of environment variables to the
- * backend.
- *
- * Returns true on success, false on failure.
- *
- * This function used to be exported for no particularly good reason.
- * Since it's no longer used by libpq itself, let's try #ifdef'ing it out
- * and see if anyone complains.
- */
-static bool
-PQsetenv(PGconn *conn)
-{
-   PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
-
-   if (!PQsetenvStart(conn))
-       return false;
-
-   for (;;)
-   {
-       /*
-        * Wait, if necessary.  Note that the initial state (just after
-        * PQsetenvStart) is to wait for the socket to select for writing.
-        */
-       switch (flag)
-       {
-           case PGRES_POLLING_OK:
-               return true;    /* success! */
-
-           case PGRES_POLLING_READING:
-               if (pqWait(1, 0, conn))
-               {
-                   conn->status = CONNECTION_BAD;
-                   return false;
-               }
-               break;
-
-           case PGRES_POLLING_WRITING:
-               if (pqWait(0, 1, conn))
-               {
-                   conn->status = CONNECTION_BAD;
-                   return false;
-               }
-               break;
-
-           default:
-               /* Just in case we failed to set it in PQsetenvPoll */
-               conn->status = CONNECTION_BAD;
-               return false;
-       }
-
-       /*
-        * Now try to advance the state machine.
-        */
-       flag = PQsetenvPoll(conn);
-   }
-}
-#endif   /* NOT_USED */
-
-
 /*
  * makeEmptyPGconn
  *  - create a PGconn data structure with (as yet) no interesting data
@@ -1869,7 +1597,6 @@ makeEmptyPGconn(void)
    conn->noticeHook = defaultNoticeProcessor;
    conn->status = CONNECTION_BAD;
    conn->asyncStatus = PGASYNC_IDLE;
-   conn->setenv_state = SETENV_STATE_IDLE;
    conn->notifyList = DLNewList();
    conn->sock = -1;
 #ifdef USE_SSL
index 84520987812e6e87147f0c49259028572850e139..53c4e2886225e7b6a1f3381ab9d77bec5c31fb0f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.132 2003/04/25 01:24:00 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.133 2003/04/25 19:45:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,8 @@
 #include "libpq-fe.h"
 #include "libpq-int.h"
 
+#include "mb/pg_wchar.h"
+
 #ifdef WIN32
 #include "win32.h"
 #else
@@ -54,6 +56,7 @@ static void handleSendFailure(PGconn *conn);
 static void handleSyncLoss(PGconn *conn, char id, int msgLength);
 static int getRowDescriptions(PGconn *conn);
 static int getAnotherTuple(PGconn *conn, int binary);
+static int getParameterStatus(PGconn *conn);
 static int getNotify(PGconn *conn);
 
 /* ---------------
@@ -950,6 +953,11 @@ parseInput(PGconn *conn)
         *
         * However, if the state is IDLE then we got trouble; we need to deal
         * with the unexpected message somehow.
+        *
+        * ParameterStatus ('S') messages are a special case: in IDLE state
+        * we must process 'em (this case could happen if a new value was
+        * adopted from config file due to SIGHUP), but otherwise we hold
+        * off until BUSY state.
         */
        if (id == 'A')
        {
@@ -970,6 +978,7 @@ parseInput(PGconn *conn)
            /*
             * Unexpected message in IDLE state; need to recover somehow.
             * ERROR messages are displayed using the notice processor;
+            * ParameterStatus is handled normally;
             * anything else is just dropped on the floor after displaying
             * a suitable warning notice.  (An ERROR is very possibly the
             * backend telling us why it is about to close the connection,
@@ -980,6 +989,11 @@ parseInput(PGconn *conn)
                if (pqGetErrorNotice(conn, false /* treat as notice */))
                    return;
            }
+           else if (id == 'S')
+           {
+               if (getParameterStatus(conn))
+                   return;
+           }
            else
            {
                snprintf(noticeWorkspace, sizeof(noticeWorkspace),
@@ -1021,6 +1035,10 @@ parseInput(PGconn *conn)
                                                      PGRES_EMPTY_QUERY);
                    conn->asyncStatus = PGASYNC_READY;
                    break;
+               case 'S':       /* parameter status */
+                   if (getParameterStatus(conn))
+                       return;
+                   break;
                case 'K':       /* secret key data from the backend */
 
                    /*
@@ -1671,6 +1689,35 @@ fail:
    return EOF;
 }
 
+/*
+ * Attempt to read a ParameterStatus message.
+ * This is possible in several places, so we break it out as a subroutine.
+ * Entry: 'S' message type and length have already been consumed.
+ * Exit: returns 0 if successfully consumed message.
+ *      returns EOF if not enough data.
+ */
+static int
+getParameterStatus(PGconn *conn)
+{
+   /* Get the parameter name */
+   if (pqGets(&conn->workBuffer, conn))
+       return EOF;
+   /* Is it one we care about? */
+   if (strcmp(conn->workBuffer.data, "client_encoding") == 0)
+   {
+       if (pqGets(&conn->workBuffer, conn))
+           return EOF;
+       conn->client_encoding = pg_char_to_encoding(conn->workBuffer.data);
+   }
+   else
+   {
+       /* Uninteresting parameter, ignore it */
+       if (pqGets(&conn->workBuffer, conn))
+           return EOF;
+   }
+   return 0;
+}
+
 /*
  * Attempt to read a Notify response message.
  * This is possible in several places, so we break it out as a subroutine.
@@ -2249,6 +2296,10 @@ PQfn(PGconn *conn,
                if (conn->result)
                    return prepareAsyncResult(conn);
                return PQmakeEmptyPGresult(conn, status);
+           case 'S':           /* parameter status */
+               if (getParameterStatus(conn))
+                   continue;
+               break;
            default:
                /* The backend violates the protocol. */
                printfPQExpBuffer(&conn->errorMessage,
index 4688fbf8f5aaef7e30f47235f185c4a281b01c6c..12670f3a0a4e694e22e3ce24de7ac87f47ea865d 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq-int.h,v 1.64 2003/04/24 21:16:44 tgl Exp $
+ * $Id: libpq-int.h,v 1.65 2003/04/25 19:45:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +56,7 @@ typedef int ssize_t;          /* ssize_t doesn't exist in VC (atleast
  * pqcomm.h describe what the backend knows, not what libpq knows.
  */
 
-#define PG_PROTOCOL_LIBPQ  PG_PROTOCOL(3,103) /* XXX temporary value */
+#define PG_PROTOCOL_LIBPQ  PG_PROTOCOL(3,104) /* XXX temporary value */
 
 /*
  * POSTGRES backend dependent Constants.
@@ -194,14 +194,6 @@ typedef enum
    PGASYNC_COPY_OUT            /* Copy Out data transfer in progress */
 }  PGAsyncStatusType;
 
-/* PGSetenvStatusType defines the state of the PQSetenv state machine */
-typedef enum
-{
-   SETENV_STATE_ENCODINGS_SEND,    /* About to send an "encodings" query */
-   SETENV_STATE_ENCODINGS_WAIT,    /* Waiting for query to complete      */
-   SETENV_STATE_IDLE
-}  PGSetenvStatusType;
-
 /* large-object-access data ... allocated only if large-object code is used. */
 typedef struct pgLobjfuncs
 {
@@ -293,9 +285,6 @@ struct pg_conn
    PGresult   *result;         /* result being constructed */
    PGresAttValue *curTuple;    /* tuple currently being read */
 
-   /* Status for sending environment info.  Used during PQSetenv only. */
-   PGSetenvStatusType setenv_state;
-
 #ifdef USE_SSL
    bool        allow_ssl_try;  /* Allowed to try SSL negotiation */
    bool        require_ssl;    /* Require SSL to make connection */