In the continuing saga of FE/BE protocol revisions, add reporting of

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.)
This commit is contained in:
Tom Lane 2003-04-25 19:45:10 +00:00
parent a2190c9eb6
commit 9cbaf72177
13 changed files with 412 additions and 478 deletions

View 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>
@ -328,7 +328,7 @@
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>
@ -900,9 +900,9 @@
<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.

View 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">

View 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>

View 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

View 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
*

View 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

View 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"
@ -52,7 +56,12 @@
#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"

View 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);

View 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 */

View 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
@ -17,32 +21,37 @@
* 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 */

View 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,45 +1548,12 @@ 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;
conn->status = CONNECTION_OK;
return PGRES_POLLING_OK;
}
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;
}
/* Unreachable */
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
@ -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

View 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,

View 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 */