mirror of
https://github.com/postgres/postgres.git
synced 2025-07-15 19:21:59 +03:00
Load and keep conversion function info when SET CLIENT_ENCODING TO is
executed to prevent database access while performing encoding conversion.
This commit is contained in:
@ -3,13 +3,14 @@
|
|||||||
* client encoding and server internal encoding.
|
* client encoding and server internal encoding.
|
||||||
* (currently mule internal code (mic) is used)
|
* (currently mule internal code (mic) is used)
|
||||||
* Tatsuo Ishii
|
* 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 "postgres.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "catalog/namespace.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];
|
static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set the client encoding. if encoding conversion between
|
* Caches for conversion function info. Note that Fcinfo.flinfo is
|
||||||
* client/server encoding is not supported, returns -1
|
* 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
|
int
|
||||||
SetClientEncoding(int encoding, bool doit)
|
SetClientEncoding(int encoding, bool doit)
|
||||||
{
|
{
|
||||||
int current_server_encoding;
|
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();
|
current_server_encoding = GetDatabaseEncoding();
|
||||||
|
|
||||||
@ -46,18 +64,35 @@ SetClientEncoding(int encoding, bool doit)
|
|||||||
* bootstrap or initprocessing mode since namespace functions will
|
* bootstrap or initprocessing mode since namespace functions will
|
||||||
* not work.
|
* not work.
|
||||||
*/
|
*/
|
||||||
if (IsNormalProcessingMode())
|
if (IsTransactionState())
|
||||||
{
|
{
|
||||||
if (!OidIsValid(FindDefaultConversionProc(encoding, current_server_encoding)) ||
|
to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding);
|
||||||
!OidIsValid(FindDefaultConversionProc(current_server_encoding, encoding)))
|
to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding);
|
||||||
return (-1);
|
|
||||||
|
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)
|
if (!doit)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ClientEncoding = &pg_enc2name_tbl[encoding];
|
if (IsTransactionState())
|
||||||
|
{
|
||||||
|
ClientEncoding = &pg_enc2name_tbl[encoding];
|
||||||
|
ToServerConvPorc = to_server;
|
||||||
|
ToClientConvPorc = to_client;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +130,6 @@ pg_get_client_encoding_name(void)
|
|||||||
* (SJIS JIS X0201 half width kanna -> UTF-8 is the worst case).
|
* (SJIS JIS X0201 half width kanna -> UTF-8 is the worst case).
|
||||||
* So "4" should be enough for the moment.
|
* So "4" should be enough for the moment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char *
|
unsigned char *
|
||||||
pg_do_encoding_conversion(unsigned char *src, int len,
|
pg_do_encoding_conversion(unsigned char *src, int len,
|
||||||
int src_encoding, int dest_encoding)
|
int src_encoding, int dest_encoding)
|
||||||
@ -231,8 +265,7 @@ pg_client_to_server(unsigned char *s, int len)
|
|||||||
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
|
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
return pg_do_encoding_conversion(s, len, ClientEncoding->encoding,
|
return perform_default_encoding_conversion(s, len, true);
|
||||||
DatabaseEncoding->encoding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -247,8 +280,54 @@ pg_server_to_client(unsigned char *s, int len)
|
|||||||
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
|
if (ClientEncoding->encoding == DatabaseEncoding->encoding)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
return pg_do_encoding_conversion(s, len, DatabaseEncoding->encoding,
|
return perform_default_encoding_conversion(s, len, false);
|
||||||
ClientEncoding->encoding);
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
/* convert a multi-byte string to a wchar */
|
||||||
|
Reference in New Issue
Block a user