Commit 9cbaf721 authored by Tom Lane's avatar Tom Lane

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.)
parent a2190c9e
<!-- $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.
......
<!--
$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">
......
<!--
$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>
......
......@@ -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
......
......@@ -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
*
......
......@@ -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
......
This diff is collapsed.
......@@ -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);
......
......@@ -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 */
......
/*
/*--------------------------------------------------------------------
* 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 */
......@@ -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
......
......@@ -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,
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment