Stephen Frost! I have modified the code to use ADD_STARTUP_OPTION instead of writing code again. And tried the patch on Windows and Linux and it works for me.
On Sun, Feb 6, 2011 at 10:19 AM, Stephen Frost <sfr...@snowman.net> wrote: > Ibrar, > > * Ibrar Ahmed (ibrar.ah...@gmail.com) wrote: > > I have reviewed/tested this patch. > > Great, thanks for that! > > > In my point code should be like this > > > > *if (conn->client_encoding_initial && > conn->client_encoding_initial[0]) > > { > > if (packet) > > { > > strcpy(packet + packet_len, "client_encoding"); > > packet_len += strlen("client_encoding") + 1; > > strcpy(packet + packet_len, > > conn->client_encoding_initial); > > packet_len += > strlen(conn->client_encoding_initial) + > > 1; > > } > > }* > > Makes sense to me, just reading through this email. Have you tested > this change..? Could you provide it as an additional patch or a new > patch including the change against head, assuming it still works well in > your testing? > > > I will test this patch on Windows and will send results. > > That would be great, it's not easy for me to test under Windows. > > Thanks! > > Stephen > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.10 (GNU/Linux) > > iEYEARECAAYFAk1O5joACgkQrzgMPqB3kijODgCeN1/PVKf/qzeuWOz82FwpR/B0 > 2rMAnR+4tCxNp9eZn7qIOTXqCv70H2oC > =vYXv > -----END PGP SIGNATURE----- > > -- Ibrar Ahmed
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 7131fb4..9223b79 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -259,6 +259,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> @@ -6355,6 +6370,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> @@ -6391,17 +6416,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 eacae71..0bf05de 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 301dc11..08c979a 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1478,7 +1478,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)); @@ -1494,8 +1494,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..cf0b91a 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -1933,6 +1933,9 @@ build_startup_packet(const PGconn *conn, char *packet, ADD_STARTUP_OPTION("application_name", val); } + if (conn->client_encoding_initial && conn->client_encoding_initial[0]) + ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial); + /* 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers