]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Load and keep conversion function info when SET CLIENT_ENCODING TO is
authorTatsuo Ishii <ishii@postgresql.org>
Thu, 8 Aug 2002 06:35:26 +0000 (06:35 +0000)
committerTatsuo Ishii <ishii@postgresql.org>
Thu, 8 Aug 2002 06:35:26 +0000 (06:35 +0000)
executed to prevent database access while performing encoding
conversion.

src/backend/utils/mb/mbutils.c

index 1ebe13ea77ea38a85067e1e6b3b8c943253922db..9b1b2021c4d11adc73474113fae5a9fd35f840a0 100644 (file)
@@ -3,13 +3,14 @@
  * 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"
 
@@ -22,13 +23,30 @@ static pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
 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();
 
@@ -46,18 +64,35 @@ SetClientEncoding(int encoding, bool doit)
         * 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;
 }
 
@@ -95,7 +130,6 @@ pg_get_client_encoding_name(void)
  * (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)
@@ -231,8 +265,7 @@ pg_client_to_server(unsigned char *s, int len)
        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);
 }
 
 /*
@@ -247,8 +280,54 @@ pg_server_to_client(unsigned char *s, int len)
        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 */