Skip to content

Commit 5f15fa8

Browse files
committed
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.
1 parent 20aae30 commit 5f15fa8

File tree

2 files changed

+108
-67
lines changed

2 files changed

+108
-67
lines changed

src/backend/commands/variable.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.74 2003/04/25 19:45:08 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.75 2003/04/27 17:31:25 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -484,10 +484,10 @@ assign_client_encoding(const char *value, bool doit, bool interactive)
484484
return NULL;
485485

486486
/*
487-
* XXX SetClientEncoding depends on namespace functions which are not
488-
* available at startup time. So we accept requested client encoding
489-
* anyway which might not be valid (e.g. no conversion procs
490-
* available).
487+
* Note: if we are in startup phase then SetClientEncoding may not be
488+
* able to really set the encoding. In this case we will assume that
489+
* the encoding is okay, and InitializeClientEncoding() will fix things
490+
* once initialization is complete.
491491
*/
492492
if (SetClientEncoding(encoding, doit) < 0)
493493
{

src/backend/utils/mb/mbutils.c

Lines changed: 103 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* (currently mule internal code (mic) is used)
55
* Tatsuo Ishii
66
*
7-
* $Header: /cvsroot/pgsql/src/backend/utils/mb/mbutils.c,v 1.39 2003/03/10 22:28:18 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/backend/utils/mb/mbutils.c,v 1.40 2003/04/27 17:31:25 tgl Exp $
88
*/
99
#include "postgres.h"
1010

@@ -32,108 +32,149 @@ static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
3232
static FmgrInfo *ToServerConvProc = NULL;
3333
static FmgrInfo *ToClientConvProc = NULL;
3434

35+
/*
36+
* During backend startup we can't set client encoding because we (a)
37+
* can't look up the conversion functions, and (b) may not know the database
38+
* encoding yet either. So SetClientEncoding() just accepts anything and
39+
* remembers it for InitializeClientEncoding() to apply later.
40+
*/
41+
static bool backend_startup_complete = false;
42+
static int pending_client_encoding = PG_SQL_ASCII;
43+
44+
3545
/* Internal functions */
3646
static unsigned char *perform_default_encoding_conversion(unsigned char *src,
3747
int len, bool is_client_to_server);
3848
static int cliplen(const unsigned char *str, int len, int limit);
3949

40-
/* Flag to we need to initialize client encoding info */
41-
static bool need_to_init_client_encoding = -1;
4250

4351
/*
4452
* Set the client encoding and save fmgrinfo for the conversion
45-
* function if necessary. if encoding conversion between client/server
46-
* encoding is not supported, returns -1
47-
*/
53+
* function if necessary. Returns 0 if okay, -1 if not (bad encoding
54+
* or can't support conversion)
55+
*/
4856
int
4957
SetClientEncoding(int encoding, bool doit)
5058
{
5159
int current_server_encoding;
5260
Oid to_server_proc,
5361
to_client_proc;
54-
FmgrInfo *to_server = NULL;
55-
FmgrInfo *to_client = NULL;
62+
FmgrInfo *to_server;
63+
FmgrInfo *to_client;
5664
MemoryContext oldcontext;
5765

58-
current_server_encoding = GetDatabaseEncoding();
59-
6066
if (!PG_VALID_FE_ENCODING(encoding))
6167
return (-1);
6268

63-
/* If we cannot actually set client encoding info, remember it
64-
* so that we could set it using InitializeClientEncoding()
65-
* in InitPostgres()
66-
*/
67-
if (current_server_encoding != encoding && !IsTransactionState())
68-
need_to_init_client_encoding = encoding;
69-
70-
if (current_server_encoding == encoding ||
71-
(current_server_encoding == PG_SQL_ASCII || encoding == PG_SQL_ASCII))
69+
/* Can't do anything during startup, per notes above */
70+
if (!backend_startup_complete)
7271
{
73-
ClientEncoding = &pg_enc2name_tbl[encoding];
72+
if (doit)
73+
pending_client_encoding = encoding;
7474
return 0;
7575
}
7676

77+
current_server_encoding = GetDatabaseEncoding();
78+
7779
/*
78-
* XXX We cannot use FindDefaultConversionProc() while in bootstrap or
79-
* initprocessing mode since namespace functions will not work.
80+
* Check for cases that require no conversion function.
8081
*/
81-
if (IsTransactionState())
82+
if (current_server_encoding == encoding ||
83+
(current_server_encoding == PG_SQL_ASCII ||
84+
encoding == PG_SQL_ASCII))
8285
{
83-
to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding);
84-
to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding);
85-
86-
if (!OidIsValid(to_server_proc) || !OidIsValid(to_client_proc))
87-
return -1;
88-
89-
/*
90-
* load the fmgr info into TopMemoryContext so that it survives
91-
* outside transaction.
92-
*/
93-
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
94-
to_server = palloc(sizeof(FmgrInfo));
95-
to_client = palloc(sizeof(FmgrInfo));
96-
fmgr_info(to_server_proc, to_server);
97-
fmgr_info(to_client_proc, to_client);
98-
MemoryContextSwitchTo(oldcontext);
86+
if (doit)
87+
{
88+
ClientEncoding = &pg_enc2name_tbl[encoding];
89+
90+
if (ToServerConvProc != NULL)
91+
{
92+
if (ToServerConvProc->fn_extra)
93+
pfree(ToServerConvProc->fn_extra);
94+
pfree(ToServerConvProc);
95+
}
96+
ToServerConvProc = NULL;
97+
98+
if (ToClientConvProc != NULL)
99+
{
100+
if (ToClientConvProc->fn_extra)
101+
pfree(ToClientConvProc->fn_extra);
102+
pfree(ToClientConvProc);
103+
}
104+
ToClientConvProc = NULL;
105+
}
106+
return 0;
99107
}
100108

109+
/*
110+
* Look up the conversion functions.
111+
*/
112+
to_server_proc = FindDefaultConversionProc(encoding,
113+
current_server_encoding);
114+
if (!OidIsValid(to_server_proc))
115+
return -1;
116+
to_client_proc = FindDefaultConversionProc(current_server_encoding,
117+
encoding);
118+
if (!OidIsValid(to_client_proc))
119+
return -1;
120+
121+
/*
122+
* Done if not wanting to actually apply setting.
123+
*/
101124
if (!doit)
102125
return 0;
103126

104-
if (IsTransactionState())
105-
{
106-
ClientEncoding = &pg_enc2name_tbl[encoding];
127+
/*
128+
* load the fmgr info into TopMemoryContext so that it survives
129+
* outside transaction.
130+
*/
131+
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
132+
to_server = palloc(sizeof(FmgrInfo));
133+
to_client = palloc(sizeof(FmgrInfo));
134+
fmgr_info(to_server_proc, to_server);
135+
fmgr_info(to_client_proc, to_client);
136+
MemoryContextSwitchTo(oldcontext);
107137

108-
if (ToServerConvProc != NULL)
109-
{
110-
if (ToServerConvProc->fn_extra)
111-
pfree(ToServerConvProc->fn_extra);
112-
pfree(ToServerConvProc);
113-
}
114-
ToServerConvProc = to_server;
138+
ClientEncoding = &pg_enc2name_tbl[encoding];
115139

116-
if (ToClientConvProc != NULL)
117-
{
118-
if (ToClientConvProc->fn_extra)
119-
pfree(ToClientConvProc->fn_extra);
120-
pfree(ToClientConvProc);
121-
}
122-
ToClientConvProc = to_client;
140+
if (ToServerConvProc != NULL)
141+
{
142+
if (ToServerConvProc->fn_extra)
143+
pfree(ToServerConvProc->fn_extra);
144+
pfree(ToServerConvProc);
145+
}
146+
ToServerConvProc = to_server;
147+
148+
if (ToClientConvProc != NULL)
149+
{
150+
if (ToClientConvProc->fn_extra)
151+
pfree(ToClientConvProc->fn_extra);
152+
pfree(ToClientConvProc);
123153
}
154+
ToClientConvProc = to_client;
155+
124156
return 0;
125157
}
126158

127-
/* Initialize client encoding if necessary.
128-
* called from InitPostgres() once during backend starting up.
159+
/*
160+
* Initialize client encoding if necessary.
161+
* called from InitPostgres() once during backend starting up.
129162
*/
130163
void
131-
InitializeClientEncoding()
164+
InitializeClientEncoding(void)
132165
{
133-
if (need_to_init_client_encoding > 0)
166+
Assert(!backend_startup_complete);
167+
backend_startup_complete = true;
168+
169+
if (SetClientEncoding(pending_client_encoding, true) < 0)
134170
{
135-
SetClientEncoding(need_to_init_client_encoding, 1);
136-
need_to_init_client_encoding = -1;
171+
/*
172+
* Oops, the requested conversion is not available.
173+
* We couldn't fail before, but we can now.
174+
*/
175+
elog(FATAL, "Conversion between %s and %s is not supported",
176+
pg_enc2name_tbl[pending_client_encoding].name,
177+
GetDatabaseEncodingName());
137178
}
138179
}
139180

0 commit comments

Comments
 (0)