Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc26ffb1

Browse files
committed
Fix SetClientEncoding() to maintain a cache of previously selected encoding
conversion functions. This allows transaction rollback to revert to aprevious client_encoding setting without doing fresh catalog lookups.I believe that this explains and fixes the recent report of "failed to commitclient_encoding" failures.This bug is present in 8.3.x, but it doesn't seem prudent to back-patchthe fix, at least not till it's had some time for field testing in HEAD.In passing, remove SetDefaultClientEncoding(), which was used nowhere.
1 parent33e7eac commitc26ffb1

File tree

2 files changed

+127
-86
lines changed

2 files changed

+127
-86
lines changed

‎src/backend/utils/mb/mbutils.c

Lines changed: 126 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
22
* This file contains public functions for conversion between
3-
* client encoding and serverinternal encoding.
4-
* (currently mule internal code (mic) is used)
3+
* client encoding and server(database) encoding.
4+
*
55
* Tatsuo Ishii
66
*
7-
* $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.82 2009/03/09 00:01:32 alvherre Exp $
7+
* $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.83 2009/04/02 17:30:53 tgl Exp $
88
*/
99
#include"postgres.h"
1010

@@ -28,23 +28,37 @@
2828
#defineMAX_CONVERSION_GROWTH 4
2929

3030
/*
31-
* We handle for actual FE and BE encoding setting encoding-identificator
32-
* and encoding-name too. It prevent searching and conversion from encoding
33-
* to encoding name in getdatabaseencoding() and other routines.
31+
* We maintain a simple linked list caching the fmgr lookup info for the
32+
* currently selected conversion functions, as well as any that have been
33+
* selected previously in the current session. (We remember previous
34+
* settings because we must be able to restore a previous setting during
35+
* transaction rollback, without doing any fresh catalog accesses.)
36+
*
37+
* Since we'll never release this data, we just keep it in TopMemoryContext.
3438
*/
35-
staticpg_enc2name*ClientEncoding=&pg_enc2name_tbl[PG_SQL_ASCII];
36-
staticpg_enc2name*DatabaseEncoding=&pg_enc2name_tbl[PG_SQL_ASCII];
39+
typedefstructConvProcInfo
40+
{
41+
ints_encoding;/* server and client encoding IDs */
42+
intc_encoding;
43+
FmgrInfoto_server_info;/* lookup info for conversion procs */
44+
FmgrInfoto_client_info;
45+
}ConvProcInfo;
46+
47+
staticList*ConvProcList=NIL;/* List of ConvProcInfo */
3748

3849
/*
39-
* Caches for conversion function info. These values are allocated in
40-
* MbProcContext. That context is a child of TopMemoryContext,
41-
* which allows these values to survive across transactions. See
42-
* SetClientEncoding() for more details.
50+
* These variables point to the currently active conversion functions,
51+
* or are NULL when no conversion is needed.
4352
*/
44-
staticMemoryContextMbProcContext=NULL;
4553
staticFmgrInfo*ToServerConvProc=NULL;
4654
staticFmgrInfo*ToClientConvProc=NULL;
4755

56+
/*
57+
* These variables track the currently selected FE and BE encodings.
58+
*/
59+
staticpg_enc2name*ClientEncoding=&pg_enc2name_tbl[PG_SQL_ASCII];
60+
staticpg_enc2name*DatabaseEncoding=&pg_enc2name_tbl[PG_SQL_ASCII];
61+
4862
/*
4963
* During backend startup we can't set client encoding because we (a)
5064
* can't look up the conversion functions, and (b) may not know the database
@@ -70,11 +84,7 @@ int
7084
SetClientEncoding(intencoding,booldoit)
7185
{
7286
intcurrent_server_encoding;
73-
Oidto_server_proc,
74-
to_client_proc;
75-
FmgrInfo*to_server;
76-
FmgrInfo*to_client;
77-
MemoryContextoldcontext;
87+
ListCell*lc;
7888

7989
if (!PG_VALID_FE_ENCODING(encoding))
8090
return-1;
@@ -101,79 +111,117 @@ SetClientEncoding(int encoding, bool doit)
101111
ClientEncoding=&pg_enc2name_tbl[encoding];
102112
ToServerConvProc=NULL;
103113
ToClientConvProc=NULL;
104-
if (MbProcContext)
105-
MemoryContextReset(MbProcContext);
106114
}
107115
return0;
108116
}
109117

110-
/*
111-
* If we're not inside a transaction then we can't do catalog lookups, so
112-
* fail. After backend startup, this could only happen if we are
113-
* re-reading postgresql.conf due to SIGHUP --- so basically this just
114-
* constrains the ability to change client_encoding on the fly from
115-
* postgresql.conf. Which would probably be a stupid thing to do anyway.
116-
*/
117-
if (!IsTransactionState())
118-
return-1;
118+
if (IsTransactionState())
119+
{
120+
/*
121+
* If we're in a live transaction, it's safe to access the catalogs,
122+
* so look up the functions. We repeat the lookup even if the info
123+
* is already cached, so that we can react to changes in the contents
124+
* of pg_conversion.
125+
*/
126+
Oidto_server_proc,
127+
to_client_proc;
128+
ConvProcInfo*convinfo;
129+
MemoryContextoldcontext;
130+
131+
to_server_proc=FindDefaultConversionProc(encoding,
132+
current_server_encoding);
133+
if (!OidIsValid(to_server_proc))
134+
return-1;
135+
to_client_proc=FindDefaultConversionProc(current_server_encoding,
136+
encoding);
137+
if (!OidIsValid(to_client_proc))
138+
return-1;
119139

120-
/*
121-
* Look up the conversion functions.
122-
*/
123-
to_server_proc=FindDefaultConversionProc(encoding,
124-
current_server_encoding);
125-
if (!OidIsValid(to_server_proc))
126-
return-1;
127-
to_client_proc=FindDefaultConversionProc(current_server_encoding,
128-
encoding);
129-
if (!OidIsValid(to_client_proc))
130-
return-1;
140+
/*
141+
* Done if not wanting to actually apply setting.
142+
*/
143+
if (!doit)
144+
return0;
131145

132-
/*
133-
* Done if not wanting to actually apply setting.
134-
*/
135-
if (!doit)
136-
return0;
146+
/*
147+
* Load the fmgr info into TopMemoryContext (could still fail here)
148+
*/
149+
convinfo= (ConvProcInfo*)MemoryContextAlloc(TopMemoryContext,
150+
sizeof(ConvProcInfo));
151+
convinfo->s_encoding=current_server_encoding;
152+
convinfo->c_encoding=encoding;
153+
fmgr_info_cxt(to_server_proc,&convinfo->to_server_info,
154+
TopMemoryContext);
155+
fmgr_info_cxt(to_client_proc,&convinfo->to_client_info,
156+
TopMemoryContext);
157+
158+
/* Attach new info to head of list */
159+
oldcontext=MemoryContextSwitchTo(TopMemoryContext);
160+
ConvProcList=lcons(convinfo,ConvProcList);
161+
MemoryContextSwitchTo(oldcontext);
137162

138-
/* Before loading the new fmgr info, remove the old info, if any */
139-
ToServerConvProc=NULL;
140-
ToClientConvProc=NULL;
141-
if (MbProcContext!=NULL)
142-
{
143-
MemoryContextReset(MbProcContext);
163+
/*
164+
* Everything is okay, so apply the setting.
165+
*/
166+
ClientEncoding=&pg_enc2name_tbl[encoding];
167+
ToServerConvProc=&convinfo->to_server_info;
168+
ToClientConvProc=&convinfo->to_client_info;
169+
170+
/*
171+
* Remove any older entry for the same encoding pair (this is just
172+
* to avoid memory leakage).
173+
*/
174+
foreach(lc,ConvProcList)
175+
{
176+
ConvProcInfo*oldinfo= (ConvProcInfo*)lfirst(lc);
177+
178+
if (oldinfo==convinfo)
179+
continue;
180+
if (oldinfo->s_encoding==convinfo->s_encoding&&
181+
oldinfo->c_encoding==convinfo->c_encoding)
182+
{
183+
ConvProcList=list_delete_ptr(ConvProcList,oldinfo);
184+
pfree(oldinfo);
185+
break;/* need not look further */
186+
}
187+
}
188+
189+
return0;/* success */
144190
}
145191
else
146192
{
147193
/*
148-
* This is the first time through, so create the context. Make it a
149-
* child of TopMemoryContext so that these values survive across
150-
* transactions.
194+
* If we're not in a live transaction, the only thing we can do
195+
* is restore a previous setting using the cache. This covers all
196+
* transaction-rollback cases. The only case it might not work for
197+
* is trying to change client_encoding on the fly by editing
198+
* postgresql.conf and SIGHUP'ing. Which would probably be a stupid
199+
* thing to do anyway.
151200
*/
152-
MbProcContext=AllocSetContextCreate(TopMemoryContext,
153-
"MbProcContext",
154-
ALLOCSET_SMALL_MINSIZE,
155-
ALLOCSET_SMALL_INITSIZE,
156-
ALLOCSET_SMALL_MAXSIZE);
157-
}
158-
159-
/* Load the fmgr info into MbProcContext */
160-
oldcontext=MemoryContextSwitchTo(MbProcContext);
161-
to_server=palloc(sizeof(FmgrInfo));
162-
to_client=palloc(sizeof(FmgrInfo));
163-
fmgr_info(to_server_proc,to_server);
164-
fmgr_info(to_client_proc,to_client);
165-
MemoryContextSwitchTo(oldcontext);
201+
foreach(lc,ConvProcList)
202+
{
203+
ConvProcInfo*oldinfo= (ConvProcInfo*)lfirst(lc);
166204

167-
ClientEncoding=&pg_enc2name_tbl[encoding];
168-
ToServerConvProc=to_server;
169-
ToClientConvProc=to_client;
205+
if (oldinfo->s_encoding==current_server_encoding&&
206+
oldinfo->c_encoding==encoding)
207+
{
208+
if (doit)
209+
{
210+
ClientEncoding=&pg_enc2name_tbl[encoding];
211+
ToServerConvProc=&oldinfo->to_server_info;
212+
ToClientConvProc=&oldinfo->to_client_info;
213+
}
214+
return0;
215+
}
216+
}
170217

171-
return0;
218+
return-1;/* it's not cached, so fail */
219+
}
172220
}
173221

174222
/*
175223
* Initialize client encoding if necessary.
176-
*called from InitPostgres() once during backendstarting up.
224+
*called from InitPostgres() once during backendstartup.
177225
*/
178226
void
179227
InitializeClientEncoding(void)
@@ -196,7 +244,8 @@ InitializeClientEncoding(void)
196244
}
197245

198246
/*
199-
* returns the current client encoding */
247+
* returns the current client encoding
248+
*/
200249
int
201250
pg_get_client_encoding(void)
202251
{
@@ -511,10 +560,9 @@ pg_server_to_client(const char *s, int len)
511560
/*
512561
*Perform default encoding conversion using cached FmgrInfo. Since
513562
*this function does not access database at all, it is safe to call
514-
*outside transactions. Explicit setting client encoding required
515-
*before calling this function. Otherwise no conversion is
516-
*performed.
517-
*/
563+
*outside transactions. If the conversion has not been set up by
564+
*SetClientEncoding(), no conversion is performed.
565+
*/
518566
staticchar*
519567
perform_default_encoding_conversion(constchar*src,intlen,boolis_client_to_server)
520568
{
@@ -919,12 +967,6 @@ pg_bind_textdomain_codeset(const char *domainname, int encoding)
919967
#endif
920968
}
921969

922-
void
923-
SetDefaultClientEncoding(void)
924-
{
925-
ClientEncoding=&pg_enc2name_tbl[GetDatabaseEncoding()];
926-
}
927-
928970
int
929971
GetDatabaseEncoding(void)
930972
{

‎src/include/mb/pg_wchar.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.87 2009/03/09 00:01:32 alvherre Exp $
9+
* $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.88 2009/04/02 17:30:53 tgl Exp $
1010
*
1111
*NOTES
1212
*This is used both by the backend and by libpq, but should not be
@@ -383,7 +383,6 @@ extern size_t wchar2char(char *to, const wchar_t *from, size_t tolen);
383383
externsize_tchar2wchar(wchar_t*to,size_ttolen,constchar*from,size_tfromlen);
384384
#endif
385385

386-
externvoidSetDefaultClientEncoding(void);
387386
externintSetClientEncoding(intencoding,booldoit);
388387
externvoidInitializeClientEncoding(void);
389388
externintpg_get_client_encoding(void);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp