* client encoding and server internal encoding.
* (currently mule internal code (mic) is used)
* Tatsuo Ishii
- * $Id: mbutils.c,v 1.29 2002/07/25 10:07:12 ishii Exp $
+ * $Id: mbutils.c,v 1.30 2002/08/08 06:35:26 ishii Exp $
*/
#include "postgres.h"
#include "access/xact.h"
#include "miscadmin.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
#include "utils/syscache.h"
#include "catalog/namespace.h"
static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
/*
- * set the client encoding. if encoding conversion between
- * client/server encoding is not supported, returns -1
+ * Caches for conversion function info. Note that Fcinfo.flinfo is
+ * allocated in TopMemoryContext so that it survives outside
+ * transactions. See SetClientEncoding() for more details.
*/
+static FmgrInfo *ToServerConvPorc = NULL;
+static FmgrInfo *ToClientConvPorc = NULL;
+
+/* Internal functions */
+static unsigned char *
+perform_default_encoding_conversion(unsigned char *src, int len, bool is_client_to_server);
+
+/*
+ * Set the client encoding and save fmgrinfo for the converion
+ * function if necessary. if encoding conversion between client/server
+ * encoding is not supported, returns -1
+*/
int
SetClientEncoding(int encoding, bool doit)
{
int current_server_encoding;
+ Oid to_server_proc, to_client_proc;
+ FmgrInfo *to_server = NULL;
+ FmgrInfo *to_client = NULL;
+ MemoryContext oldcontext;
current_server_encoding = GetDatabaseEncoding();
* bootstrap or initprocessing mode since namespace functions will
* not work.
*/
- if (IsNormalProcessingMode())
+ if (IsTransactionState())
{
- if (!OidIsValid(FindDefaultConversionProc(encoding, current_server_encoding)) ||
- !OidIsValid(FindDefaultConversionProc(current_server_encoding, encoding)))
- return (-1);
+ to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding);
+ to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding);
+
+ if (!OidIsValid(to_server_proc) || !OidIsValid(to_client_proc))
+ return -1;
+
+ /*
+ * load the fmgr info into TopMemoryContext so that it
+ * survives outside transaction.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ to_server = palloc(sizeof(FmgrInfo));
+ to_client = palloc(sizeof(FmgrInfo));
+ fmgr_info(to_server_proc, to_server);
+ fmgr_info(to_client_proc, to_client);
+ MemoryContextSwitchTo(oldcontext);
}
if (!doit)
return 0;
- ClientEncoding = &pg_enc2name_tbl[encoding];
-
+ if (IsTransactionState())
+ {
+ ClientEncoding = &pg_enc2name_tbl[encoding];
+ ToServerConvPorc = to_server;
+ ToClientConvPorc = to_client;
+ }
return 0;
}
* (SJIS JIS X0201 half width kanna -> UTF-8 is the worst case).
* So "4" should be enough for the moment.
*/
-
unsigned char *
pg_do_encoding_conversion(unsigned char *src, int len,
int src_encoding, int dest_encoding)
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
return s;
- return pg_do_encoding_conversion(s, len, ClientEncoding->encoding,
- DatabaseEncoding->encoding);
+ return perform_default_encoding_conversion(s, len, true);
}
/*
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
return s;
- return pg_do_encoding_conversion(s, len, DatabaseEncoding->encoding,
- ClientEncoding->encoding);
+ return perform_default_encoding_conversion(s, len, false);
+}
+
+/*
+ * Perform default encoding conversion using cached FmgrInfo. Since
+ * this function does not access database at all, it is safe to call
+ * outside transactions. Explicit setting client encoding required
+ * before calling this function. Otherwise no conversion is
+ * performed.
+*/
+static unsigned char *
+perform_default_encoding_conversion(unsigned char *src, int len, bool is_client_to_server)
+{
+ unsigned char *result;
+ int src_encoding, dest_encoding;
+ FmgrInfo *flinfo;
+
+ if (is_client_to_server)
+ {
+ src_encoding = ClientEncoding->encoding;
+ dest_encoding = DatabaseEncoding->encoding;
+ flinfo = ToServerConvPorc;
+ }
+ else
+ {
+ src_encoding = DatabaseEncoding->encoding;
+ dest_encoding = ClientEncoding->encoding;
+ flinfo = ToClientConvPorc;
+ }
+
+ if (flinfo == NULL)
+ return src;
+
+ if (src_encoding == dest_encoding)
+ return src;
+
+ if (src_encoding == PG_SQL_ASCII || dest_encoding == PG_SQL_ASCII)
+ return src;
+
+ result = palloc(len * 4 + 1);
+
+ FunctionCall5(flinfo,
+ Int32GetDatum(src_encoding),
+ Int32GetDatum(dest_encoding),
+ CStringGetDatum(src),
+ CStringGetDatum(result),
+ Int32GetDatum(len));
+ return result;
}
/* convert a multi-byte string to a wchar */