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];
2223static 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 unsignedchar *
35+ perform_default_encoding_conversion (unsignedchar * 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+ */
2842int
2943SetClientEncoding (int encoding ,bool doit )
3044{
3145int 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
3351current_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
5687if (!doit )
5788return 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+ }
6196return 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-
99133unsignedchar *
100134pg_do_encoding_conversion (unsignedchar * src ,int len ,
101135int src_encoding ,int dest_encoding )
@@ -231,8 +265,7 @@ pg_client_to_server(unsigned char *s, int len)
231265if (ClientEncoding -> encoding == DatabaseEncoding -> encoding )
232266return 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)
247280if (ClientEncoding -> encoding == DatabaseEncoding -> encoding )
248281return 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 unsignedchar *
294+ perform_default_encoding_conversion (unsignedchar * src ,int len ,bool is_client_to_server )
295+ {
296+ unsignedchar * 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 */