On lör, 2009-07-25 at 01:41 -0500, Jaime Casanova wrote:
> On Fri, Jul 24, 2009 at 2:23 AM, Magnus Hagander<[email protected]> wrote:
> >>
> >> 1) it introduces a dependency for -lpgport when compiling a client
> >> that uses libpq
> >> http://archives.postgresql.org/pgsql-hackers/2009-07/msg01511.php
> >
> > For other parts of libpgport that are needed, we pull in the
> > individual source files. We specifically *don't* link libpq with
> > libpgport, for a reason. There's a comment in the Makefile that
> > explains why.
> >
>
> ok, attached a version that modifies src/interfaces/libpq/Makefile to
> push chklocale.o and eliminate the dependency on libpgport, this
> change also fixes the compile problem on windows
I have adjusted your old patch for the current tree, and it seems to
work. I think it was just forgotten last time because the move to
PQconnectdbParams had to happen first. But I'll throw it back into the
ring now.
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index fe661b8..cb3f6e3 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -245,6 +245,21 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand
</listitem>
</varlistentry>
+ <varlistentry id="libpq-connect-client-encoding" xreflabel="client_encoding">
+ <term><literal>client_encoding</literal></term>
+ <listitem>
+ <para>
+ This sets the <varname>client_encoding</varname>
+ configuration parameter for this connection. In addition to
+ the values accepted by the corresponding server option, you
+ can use <literal>auto</literal> to determine the right
+ encoding from the current locale in the client
+ (<envar>LC_CTYPE</envar> environment variable on Unix
+ systems).
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-connect-options" xreflabel="options">
<term><literal>options</literal></term>
<listitem>
@@ -6341,6 +6356,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
linkend="libpq-connect-connect-timeout"> connection parameter.
</para>
</listitem>
+
+ <listitem>
+ <para>
+ <indexterm>
+ <primary><envar>PGCLIENTENCODING</envar></primary>
+ </indexterm>
+ <envar>PGCLIENTENCODING</envar> behaves the same as <xref
+ linkend="libpq-connect-client-encoding"> connection parameter.
+ </para>
+ </listitem>
</itemizedlist>
</para>
@@ -6377,17 +6402,6 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
<listitem>
<para>
<indexterm>
- <primary><envar>PGCLIENTENCODING</envar></primary>
- </indexterm>
- <envar>PGCLIENTENCODING</envar> sets the default client character
- set encoding. (Equivalent to <literal>SET client_encoding TO
- ...</literal>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- <indexterm>
<primary><envar>PGGEQO</envar></primary>
</indexterm>
<envar>PGGEQO</envar> sets the default mode for the genetic query
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 5f61561..1716b3b 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -593,6 +593,17 @@ $ <userinput>psql "service=myservice sslmode=require"</userinput>
privileges, server is not running on the targeted host, etc.),
<application>psql</application> will return an error and terminate.
</para>
+
+ <para>
+ If at least one of standard input or standard output are a
+ terminal, then <application>psql</application> sets the client
+ encoding to <quote>auto</quote>, which will detect the
+ appropriate client encoding from the locale settings
+ (<envar>LC_CTYPE</envar> environment variable on Unix systems).
+ If this doesn't work out as expected, the client encoding can be
+ overridden using the environment
+ variable <envar>PGCLIENTENCODING</envar>.
+ </para>
</refsect2>
<refsect2 id="R2-APP-PSQL-4">
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 962c13c..37f696a 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1475,7 +1475,7 @@ do_connect(char *dbname, char *user, char *host, char *port)
while (true)
{
-#define PARAMS_ARRAY_SIZE 7
+#define PARAMS_ARRAY_SIZE 8
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
@@ -1491,8 +1491,10 @@ do_connect(char *dbname, char *user, char *host, char *port)
values[4] = dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
- keywords[6] = NULL;
- values[6] = NULL;
+ keywords[6] = "client_encoding";
+ values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
+ keywords[7] = NULL;
+ values[7] = NULL;
n_conn = PQconnectdbParams(keywords, values, true);
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 4f3815a..539f8be 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -171,7 +171,7 @@ main(int argc, char *argv[])
/* loop until we have a password if requested by backend */
do
{
-#define PARAMS_ARRAY_SIZE 7
+#define PARAMS_ARRAY_SIZE 8
const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
@@ -189,8 +189,10 @@ main(int argc, char *argv[])
"postgres" : options.dbname;
keywords[5] = "fallback_application_name";
values[5] = pset.progname;
- keywords[6] = NULL;
- values[6] = NULL;
+ keywords[6] = "client_encoding";
+ values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
+ keywords[7] = NULL;
+ values[7] = NULL;
new_pass = false;
pset.db = PQconnectdbParams(keywords, values, true);
diff --git a/src/interfaces/libpq/.gitignore b/src/interfaces/libpq/.gitignore
index 366adeb..29024ae 100644
--- a/src/interfaces/libpq/.gitignore
+++ b/src/interfaces/libpq/.gitignore
@@ -1,4 +1,5 @@
/exports.list
+/chklocale.c
/crypt.c
/getaddrinfo.c
/inet_aton.c
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index f4111c4..1879544 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -35,7 +35,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
libpq-events.o
# libpgport C files we always use
-OBJS += inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o
+OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o
# libpgport C files that are needed if identified by configure
OBJS += $(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
# backend/libpq
@@ -88,7 +88,7 @@ backend_src = $(top_srcdir)/src/backend
# For some libpgport modules, this only happens if configure decides
# the module is needed (see filter hack in OBJS, above).
-crypt.c getaddrinfo.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c: % : $(top_srcdir)/src/port/%
+chklocale.c crypt.c getaddrinfo.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .
ip.c md5.c: % : $(backend_src)/libpq/%
@@ -135,7 +135,7 @@ clean distclean: clean-lib
# Might be left over from a Win32 client-only build
rm -f pg_config_paths.h
rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c thread.c
- rm -f crypt.c getaddrinfo.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c
+ rm -f chklocale.c crypt.c getaddrinfo.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c
rm -f pgsleep.c
rm -f md5.c ip.c
rm -f encnames.c wchar.c
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b8013ed..b3dd9e8 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -175,6 +175,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
{"port", "PGPORT", DEF_PGPORT_STR, NULL,
"Database-Port", "", 6},
+ {"client_encoding", "PGCLIENTENCODING", NULL, NULL,
+ "Client-Encoding", "", 10},
+
/*
* "tty" is no longer used either, but keep it present for backwards
* compatibility.
@@ -270,9 +273,6 @@ static const PQEnvironmentOption EnvironmentOptions[] =
{
"PGTZ", "timezone"
},
- {
- "PGCLIENTENCODING", "client_encoding"
- },
/* internal performance-related settings */
{
"PGGEQO", "geqo"
@@ -612,6 +612,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
conn->pgpass = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "connect_timeout");
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "client_encoding");
+ conn->client_encoding_initial = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "keepalives");
conn->keepalives = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "keepalives_idle");
@@ -787,6 +789,16 @@ connectOptions2(PGconn *conn)
conn->sslmode = strdup(DefaultSSLMode);
/*
+ * Resolve special "auto" client_encoding from the locale
+ */
+ if (conn->client_encoding_initial &&
+ strcmp(conn->client_encoding_initial, "auto") == 0)
+ {
+ free(conn->client_encoding_initial);
+ conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL)));
+ }
+
+ /*
* Only if we get this far is it appropriate to try to connect. (We need a
* state flag, rather than just the boolean result of this function, in
* case someone tries to PQreset() the PGconn.)
@@ -2508,7 +2520,7 @@ keep_going: /* We will come back to here until there is
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
conn->status = CONNECTION_SETENV;
- conn->setenv_state = SETENV_STATE_OPTION_SEND;
+ conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND;
conn->next_eo = EnvironmentOptions;
return PGRES_POLLING_WRITING;
}
@@ -4661,6 +4673,10 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
if (!encoding)
return -1;
+ /* Resolve special "auto" value from the locale */
+ if (strcmp(encoding, "auto") == 0)
+ encoding = pg_encoding_to_char(pg_get_encoding_from_locale(NULL));
+
/* check query buffer overflow */
if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
return -1;
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 058a25b..6e2bcfd 100644
--- a/src/interfaces/libpq/fe-protocol2.c
+++ b/src/interfaces/libpq/fe-protocol2.c
@@ -58,6 +58,7 @@ pqSetenvPoll(PGconn *conn)
switch (conn->setenv_state)
{
/* These are reading states */
+ case SETENV_STATE_CLIENT_ENCODING_WAIT:
case SETENV_STATE_OPTION_WAIT:
case SETENV_STATE_QUERY1_WAIT:
case SETENV_STATE_QUERY2_WAIT:
@@ -74,6 +75,7 @@ pqSetenvPoll(PGconn *conn)
}
/* These are writing states, so we just proceed. */
+ case SETENV_STATE_CLIENT_ENCODING_SEND:
case SETENV_STATE_OPTION_SEND:
case SETENV_STATE_QUERY1_SEND:
case SETENV_STATE_QUERY2_SEND:
@@ -98,6 +100,34 @@ pqSetenvPoll(PGconn *conn)
{
switch (conn->setenv_state)
{
+ case SETENV_STATE_CLIENT_ENCODING_SEND:
+ {
+ char setQuery[100]; /* note length limit in
+ * sprintf below */
+ const char *val = conn->client_encoding_initial;
+
+ if (val)
+ {
+ if (pg_strcasecmp(val, "default") == 0)
+ sprintf(setQuery, "SET client_encoding = DEFAULT");
+ else
+ sprintf(setQuery, "SET client_encoding = '%.60s'",
+ val);
+#ifdef CONNECTDEBUG
+ fprintf(stderr,
+ "Sending client_encoding with %s\n",
+ setQuery);
+#endif
+ if (!PQsendQuery(conn, setQuery))
+ goto error_return;
+
+ conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT;
+ }
+ else
+ conn->setenv_state = SETENV_STATE_OPTION_SEND;
+ break;
+ }
+
case SETENV_STATE_OPTION_SEND:
{
/*
@@ -142,6 +172,31 @@ pqSetenvPoll(PGconn *conn)
break;
}
+ case SETENV_STATE_CLIENT_ENCODING_WAIT:
+ {
+ if (PQisBusy(conn))
+ return PGRES_POLLING_READING;
+
+ res = PQgetResult(conn);
+
+ if (res)
+ {
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ PQclear(res);
+ goto error_return;
+ }
+ PQclear(res);
+ /* Keep reading until PQgetResult returns NULL */
+ }
+ else
+ {
+ /* Query finished, so send the next option */
+ conn->setenv_state = SETENV_STATE_OPTION_SEND;
+ }
+ break;
+ }
+
case SETENV_STATE_OPTION_WAIT:
{
if (PQisBusy(conn))
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 2a8dbdf..8ee38b6 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1932,6 +1932,15 @@ build_startup_packet(const PGconn *conn, char *packet,
if (val && val[0])
ADD_STARTUP_OPTION("application_name", val);
}
+ if (conn->client_encoding_initial && conn->client_encoding_initial[0])
+ {
+ if (packet)
+ strcpy(packet + packet_len, "client_encoding");
+ packet_len += strlen("client_encoding") + 1;
+ if (packet)
+ strcpy(packet + packet_len, conn->client_encoding_initial);
+ packet_len += strlen(conn->client_encoding_initial) + 1;
+ }
/* Add any environment-driven GUC settings needed */
for (next_eo = options; next_eo->envName; next_eo++)
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index e9a2b71..25c779a 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -235,6 +235,8 @@ typedef enum
/* (this is used only for 2.0-protocol connections) */
typedef enum
{
+ SETENV_STATE_CLIENT_ENCODING_SEND, /* About to send an Environment Option */
+ SETENV_STATE_CLIENT_ENCODING_WAIT, /* Waiting for above send to complete */
SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */
SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */
SETENV_STATE_QUERY1_SEND, /* About to send a status query */
@@ -293,6 +295,7 @@ struct pg_conn
char *pgtty; /* tty on which the backend messages is
* displayed (OBSOLETE, NOT USED) */
char *connect_timeout; /* connection timeout (numeric string) */
+ char *client_encoding_initial; /* encoding to use */
char *pgoptions; /* options to start the backend with */
char *appname; /* application name */
char *fbappname; /* fallback application name */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers