Commit 5f15fa8d authored by Tom Lane's avatar Tom Lane

Clean up some problems in SetClientEncoding: failed to honor doit flag

in all cases, leaked TopMemoryContext memory in others.  Make the
interaction between SetClientEncoding and InitializeClientEncoding
cleaner and better documented.  I suspect these changes should be
back-patched into 7.3, but will wait on Tatsuo's verification.
parent 20aae304
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.74 2003/04/25 19:45:08 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.75 2003/04/27 17:31:25 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -484,10 +484,10 @@ assign_client_encoding(const char *value, bool doit, bool interactive) ...@@ -484,10 +484,10 @@ assign_client_encoding(const char *value, bool doit, bool interactive)
return NULL; return NULL;
/* /*
* XXX SetClientEncoding depends on namespace functions which are not * Note: if we are in startup phase then SetClientEncoding may not be
* available at startup time. So we accept requested client encoding * able to really set the encoding. In this case we will assume that
* anyway which might not be valid (e.g. no conversion procs * the encoding is okay, and InitializeClientEncoding() will fix things
* available). * once initialization is complete.
*/ */
if (SetClientEncoding(encoding, doit) < 0) if (SetClientEncoding(encoding, doit) < 0)
{ {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* (currently mule internal code (mic) is used) * (currently mule internal code (mic) is used)
* Tatsuo Ishii * Tatsuo Ishii
* *
* $Header: /cvsroot/pgsql/src/backend/utils/mb/mbutils.c,v 1.39 2003/03/10 22:28:18 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/mb/mbutils.c,v 1.40 2003/04/27 17:31:25 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -32,60 +32,98 @@ static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII]; ...@@ -32,60 +32,98 @@ static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
static FmgrInfo *ToServerConvProc = NULL; static FmgrInfo *ToServerConvProc = NULL;
static FmgrInfo *ToClientConvProc = NULL; static FmgrInfo *ToClientConvProc = NULL;
/*
* During backend startup we can't set client encoding because we (a)
* can't look up the conversion functions, and (b) may not know the database
* encoding yet either. So SetClientEncoding() just accepts anything and
* remembers it for InitializeClientEncoding() to apply later.
*/
static bool backend_startup_complete = false;
static int pending_client_encoding = PG_SQL_ASCII;
/* Internal functions */ /* Internal functions */
static unsigned char *perform_default_encoding_conversion(unsigned char *src, static unsigned char *perform_default_encoding_conversion(unsigned char *src,
int len, bool is_client_to_server); int len, bool is_client_to_server);
static int cliplen(const unsigned char *str, int len, int limit); static int cliplen(const unsigned char *str, int len, int limit);
/* Flag to we need to initialize client encoding info */
static bool need_to_init_client_encoding = -1;
/* /*
* Set the client encoding and save fmgrinfo for the conversion * Set the client encoding and save fmgrinfo for the conversion
* function if necessary. if encoding conversion between client/server * function if necessary. Returns 0 if okay, -1 if not (bad encoding
* encoding is not supported, returns -1 * or can't support conversion)
*/ */
int int
SetClientEncoding(int encoding, bool doit) SetClientEncoding(int encoding, bool doit)
{ {
int current_server_encoding; int current_server_encoding;
Oid to_server_proc, Oid to_server_proc,
to_client_proc; to_client_proc;
FmgrInfo *to_server = NULL; FmgrInfo *to_server;
FmgrInfo *to_client = NULL; FmgrInfo *to_client;
MemoryContext oldcontext; MemoryContext oldcontext;
current_server_encoding = GetDatabaseEncoding();
if (!PG_VALID_FE_ENCODING(encoding)) if (!PG_VALID_FE_ENCODING(encoding))
return (-1); return (-1);
/* If we cannot actually set client encoding info, remember it /* Can't do anything during startup, per notes above */
* so that we could set it using InitializeClientEncoding() if (!backend_startup_complete)
* in InitPostgres() {
*/ if (doit)
if (current_server_encoding != encoding && !IsTransactionState()) pending_client_encoding = encoding;
need_to_init_client_encoding = encoding; return 0;
}
current_server_encoding = GetDatabaseEncoding();
/*
* Check for cases that require no conversion function.
*/
if (current_server_encoding == encoding || if (current_server_encoding == encoding ||
(current_server_encoding == PG_SQL_ASCII || encoding == PG_SQL_ASCII)) (current_server_encoding == PG_SQL_ASCII ||
encoding == PG_SQL_ASCII))
{
if (doit)
{ {
ClientEncoding = &pg_enc2name_tbl[encoding]; ClientEncoding = &pg_enc2name_tbl[encoding];
if (ToServerConvProc != NULL)
{
if (ToServerConvProc->fn_extra)
pfree(ToServerConvProc->fn_extra);
pfree(ToServerConvProc);
}
ToServerConvProc = NULL;
if (ToClientConvProc != NULL)
{
if (ToClientConvProc->fn_extra)
pfree(ToClientConvProc->fn_extra);
pfree(ToClientConvProc);
}
ToClientConvProc = NULL;
}
return 0; return 0;
} }
/* /*
* XXX We cannot use FindDefaultConversionProc() while in bootstrap or * Look up the conversion functions.
* initprocessing mode since namespace functions will not work.
*/ */
if (IsTransactionState()) to_server_proc = FindDefaultConversionProc(encoding,
{ current_server_encoding);
to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding); if (!OidIsValid(to_server_proc))
to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding); return -1;
to_client_proc = FindDefaultConversionProc(current_server_encoding,
if (!OidIsValid(to_server_proc) || !OidIsValid(to_client_proc)) encoding);
if (!OidIsValid(to_client_proc))
return -1; return -1;
/*
* Done if not wanting to actually apply setting.
*/
if (!doit)
return 0;
/* /*
* load the fmgr info into TopMemoryContext so that it survives * load the fmgr info into TopMemoryContext so that it survives
* outside transaction. * outside transaction.
...@@ -96,13 +134,7 @@ SetClientEncoding(int encoding, bool doit) ...@@ -96,13 +134,7 @@ SetClientEncoding(int encoding, bool doit)
fmgr_info(to_server_proc, to_server); fmgr_info(to_server_proc, to_server);
fmgr_info(to_client_proc, to_client); fmgr_info(to_client_proc, to_client);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
}
if (!doit)
return 0;
if (IsTransactionState())
{
ClientEncoding = &pg_enc2name_tbl[encoding]; ClientEncoding = &pg_enc2name_tbl[encoding];
if (ToServerConvProc != NULL) if (ToServerConvProc != NULL)
...@@ -120,20 +152,29 @@ SetClientEncoding(int encoding, bool doit) ...@@ -120,20 +152,29 @@ SetClientEncoding(int encoding, bool doit)
pfree(ToClientConvProc); pfree(ToClientConvProc);
} }
ToClientConvProc = to_client; ToClientConvProc = to_client;
}
return 0; return 0;
} }
/* Initialize client encoding if necessary. /*
* Initialize client encoding if necessary.
* called from InitPostgres() once during backend starting up. * called from InitPostgres() once during backend starting up.
*/ */
void void
InitializeClientEncoding() InitializeClientEncoding(void)
{ {
if (need_to_init_client_encoding > 0) Assert(!backend_startup_complete);
backend_startup_complete = true;
if (SetClientEncoding(pending_client_encoding, true) < 0)
{ {
SetClientEncoding(need_to_init_client_encoding, 1); /*
need_to_init_client_encoding = -1; * Oops, the requested conversion is not available.
* We couldn't fail before, but we can now.
*/
elog(FATAL, "Conversion between %s and %s is not supported",
pg_enc2name_tbl[pending_client_encoding].name,
GetDatabaseEncodingName());
} }
} }
......
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