Skip to content

Commit 3c63578

Browse files
committed
Load and keep conversion function info when SET CLIENT_ENCODING TO is
executed to prevent database access while performing encoding conversion.
1 parent b53c851 commit 3c63578

File tree

1 file changed

+93
-14
lines changed

1 file changed

+93
-14
lines changed

src/backend/utils/mb/mbutils.c

Lines changed: 93 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* client encoding and server internal encoding.
44
* (currently mule internal code (mic) is used)
55
* Tatsuo Ishii
6-
* $Id: mbutils.c,v 1.29 2002/07/25 10:07:12 ishii Exp $
6+
* $Id: mbutils.c,v 1.30 2002/08/08 06:35:26 ishii Exp $
77
*/
88
#include "postgres.h"
99
#include "access/xact.h"
1010
#include "miscadmin.h"
1111
#include "mb/pg_wchar.h"
1212
#include "utils/builtins.h"
13+
#include "utils/memutils.h"
1314
#include "utils/syscache.h"
1415
#include "catalog/namespace.h"
1516

@@ -22,13 +23,30 @@ static pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
2223
static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
2324

2425
/*
25-
* set the client encoding. if encoding conversion between
26-
* client/server encoding is not supported, returns -1
26+
* Caches for conversion function info. Note that Fcinfo.flinfo is
27+
* allocated in TopMemoryContext so that it survives outside
28+
* transactions. See SetClientEncoding() for more details.
2729
*/
30+
static FmgrInfo *ToServerConvPorc = NULL;
31+
static FmgrInfo *ToClientConvPorc = NULL;
32+
33+
/* Internal functions */
34+
static unsigned char *
35+
perform_default_encoding_conversion(unsigned char *src, int len, bool is_client_to_server);
36+
37+
/*
38+
* Set the client encoding and save fmgrinfo for the converion
39+
* function if necessary. if encoding conversion between client/server
40+
* encoding is not supported, returns -1
41+
*/
2842
int
2943
SetClientEncoding(int encoding, bool doit)
3044
{
3145
int current_server_encoding;
46+
Oid to_server_proc, to_client_proc;
47+
FmgrInfo *to_server = NULL;
48+
FmgrInfo *to_client = NULL;
49+
MemoryContext oldcontext;
3250

3351
current_server_encoding = GetDatabaseEncoding();
3452

@@ -46,18 +64,35 @@ SetClientEncoding(int encoding, bool doit)
4664
* bootstrap or initprocessing mode since namespace functions will
4765
* not work.
4866
*/
49-
if (IsNormalProcessingMode())
67+
if (IsTransactionState())
5068
{
51-
if (!OidIsValid(FindDefaultConversionProc(encoding, current_server_encoding)) ||
52-
!OidIsValid(FindDefaultConversionProc(current_server_encoding, encoding)))
53-
return (-1);
69+
to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding);
70+
to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding);
71+
72+
if (!OidIsValid(to_server_proc) || !OidIsValid(to_client_proc))
73+
return -1;
74+
75+
/*
76+
* load the fmgr info into TopMemoryContext so that it
77+
* survives outside transaction.
78+
*/
79+
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
80+
to_server = palloc(sizeof(FmgrInfo));
81+
to_client = palloc(sizeof(FmgrInfo));
82+
fmgr_info(to_server_proc, to_server);
83+
fmgr_info(to_client_proc, to_client);
84+
MemoryContextSwitchTo(oldcontext);
5485
}
5586

5687
if (!doit)
5788
return 0;
5889

59-
ClientEncoding = &pg_enc2name_tbl[encoding];
60-
90+
if (IsTransactionState())
91+
{
92+
ClientEncoding = &pg_enc2name_tbl[encoding];
93+
ToServerConvPorc = to_server;
94+
ToClientConvPorc = to_client;
95+
}
6196
return 0;
6297
}
6398

@@ -95,7 +130,6 @@ pg_get_client_encoding_name(void)
95130
* (SJIS JIS X0201 half width kanna -> UTF-8 is the worst case).
96131
* So "4" should be enough for the moment.
97132
*/
98-
99133
unsigned char *
100134
pg_do_encoding_conversion(unsigned char *src, int len,
101135
int src_encoding, int dest_encoding)
@@ -231,8 +265,7 @@ pg_client_to_server(unsigned char *s, int len)
231265
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
232266
return s;
233267

234-
return pg_do_encoding_conversion(s, len, ClientEncoding->encoding,
235-
DatabaseEncoding->encoding);
268+
return perform_default_encoding_conversion(s, len, true);
236269
}
237270

238271
/*
@@ -247,8 +280,54 @@ pg_server_to_client(unsigned char *s, int len)
247280
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
248281
return s;
249282

250-
return pg_do_encoding_conversion(s, len, DatabaseEncoding->encoding,
251-
ClientEncoding->encoding);
283+
return perform_default_encoding_conversion(s, len, false);
284+
}
285+
286+
/*
287+
* Perform default encoding conversion using cached FmgrInfo. Since
288+
* this function does not access database at all, it is safe to call
289+
* outside transactions. Explicit setting client encoding required
290+
* before calling this function. Otherwise no conversion is
291+
* performed.
292+
*/
293+
static unsigned char *
294+
perform_default_encoding_conversion(unsigned char *src, int len, bool is_client_to_server)
295+
{
296+
unsigned char *result;
297+
int src_encoding, dest_encoding;
298+
FmgrInfo *flinfo;
299+
300+
if (is_client_to_server)
301+
{
302+
src_encoding = ClientEncoding->encoding;
303+
dest_encoding = DatabaseEncoding->encoding;
304+
flinfo = ToServerConvPorc;
305+
}
306+
else
307+
{
308+
src_encoding = DatabaseEncoding->encoding;
309+
dest_encoding = ClientEncoding->encoding;
310+
flinfo = ToClientConvPorc;
311+
}
312+
313+
if (flinfo == NULL)
314+
return src;
315+
316+
if (src_encoding == dest_encoding)
317+
return src;
318+
319+
if (src_encoding == PG_SQL_ASCII || dest_encoding == PG_SQL_ASCII)
320+
return src;
321+
322+
result = palloc(len * 4 + 1);
323+
324+
FunctionCall5(flinfo,
325+
Int32GetDatum(src_encoding),
326+
Int32GetDatum(dest_encoding),
327+
CStringGetDatum(src),
328+
CStringGetDatum(result),
329+
Int32GetDatum(len));
330+
return result;
252331
}
253332

254333
/* convert a multi-byte string to a wchar */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy