diff -cpr head/src/backend/storage/file/fd.c server-side_encoding_issues/src/backend/storage/file/fd.c
*** head/src/backend/storage/file/fd.c	Thu Mar  5 13:14:27 2009
--- server-side_encoding_issues/src/backend/storage/file/fd.c	Wed Apr 15 13:54:46 2009
***************
*** 49,54 ****
--- 49,55 ----
  #include <sys/resource.h>		/* for getrlimit */
  #endif
  
+ #include "mb/pg_wchar.h"
  #include "miscadmin.h"
  #include "access/xact.h"
  #include "catalog/pg_tablespace.h"
*************** int
*** 494,505 ****
  BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
  {
  	int			fd;
  
  tryAgain:
! 	fd = open(fileName, fileFlags, fileMode);
  
  	if (fd >= 0)
  		return fd;				/* success! */
  
  	if (errno == EMFILE || errno == ENFILE)
  	{
--- 495,513 ----
  BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
  {
  	int			fd;
+ 	char	   *path;
+ 
+ 	path = pg_server_to_platform(fileName, true);
  
  tryAgain:
! 	fd = open(path, fileFlags, fileMode);
  
  	if (fd >= 0)
+ 	{
+ 		if (path != fileName)
+ 			pfree(path);
  		return fd;				/* success! */
+ 	}
  
  	if (errno == EMFILE || errno == ENFILE)
  	{
*************** tryAgain:
*** 514,519 ****
--- 522,529 ----
  		errno = save_errno;
  	}
  
+ 	if (path != fileName)
+ 		pfree(path);
  	return -1;					/* failure */
  }
  
*************** FILE *
*** 1336,1345 ****
--- 1346,1358 ----
  AllocateFile(const char *name, const char *mode)
  {
  	FILE	   *file;
+ 	char	   *path;
  
  	DO_DB(elog(LOG, "AllocateFile: Allocated %d (%s)",
  			   numAllocatedDescs, name));
  
+ 	path = pg_server_to_platform(name, true);
+ 
  	/*
  	 * The test against MAX_ALLOCATED_DESCS prevents us from overflowing
  	 * allocatedFiles[]; the test against max_safe_fds prevents AllocateFile
*************** AllocateFile(const char *name, const cha
*** 1351,1357 ****
  		elog(ERROR, "too many private files demanded");
  
  TryAgain:
! 	if ((file = fopen(name, mode)) != NULL)
  	{
  		AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];
  
--- 1364,1370 ----
  		elog(ERROR, "too many private files demanded");
  
  TryAgain:
! 	if ((file = fopen(path, mode)) != NULL)
  	{
  		AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];
  
*************** TryAgain:
*** 1359,1364 ****
--- 1372,1379 ----
  		desc->desc.file = file;
  		desc->create_subid = GetCurrentSubTransactionId();
  		numAllocatedDescs++;
+ 		if (path != name)
+ 			pfree(path);
  		return desc->desc.file;
  	}
  
*************** TryAgain:
*** 1375,1380 ****
--- 1390,1397 ----
  		errno = save_errno;
  	}
  
+ 	if (path != name)
+ 		pfree(path);
  	return NULL;
  }
  
diff -cpr head/src/backend/utils/error/elog.c server-side_encoding_issues/src/backend/utils/error/elog.c
*** head/src/backend/utils/error/elog.c	Wed Mar  4 09:51:28 2009
--- server-side_encoding_issues/src/backend/utils/error/elog.c	Wed Apr 15 13:54:46 2009
*************** extern bool redirection_done;
*** 86,91 ****
--- 86,92 ----
  int			Log_error_verbosity = PGERROR_VERBOSE;
  char	   *Log_line_prefix = NULL;		/* format for extra log line info */
  int			Log_destination = LOG_DESTINATION_STDERR;
+ int			Log_encoding = PG_SQL_ASCII;
  
  #ifdef HAVE_SYSLOG
  
*************** static const char *error_severity(int el
*** 148,153 ****
--- 149,155 ----
  static void append_with_tabs(StringInfo buf, const char *str);
  static bool is_log_level_output(int elevel, int log_min_level);
  static void write_pipe_chunks(char *data, int len, int dest);
+ static void write_pipe_chunks_conv(char *data, int len, int dest);
  static void write_csvlog(ErrorData *edata);
  static void setup_formatted_log_time(void);
  static void setup_formatted_start_time(void);
*************** write_csvlog(ErrorData *edata)
*** 1940,1946 ****
  	if (am_syslogger)
  		write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
  	else
! 		write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
  
  	pfree(buf.data);
  }
--- 1942,1948 ----
  	if (am_syslogger)
  		write_syslogger_file(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
  	else
! 		write_pipe_chunks_conv(buf.data, buf.len, LOG_DESTINATION_CSVLOG);
  
  	pfree(buf.data);
  }
*************** unpack_sql_state(int sql_state)
*** 1965,1970 ****
--- 1967,1989 ----
  	return buf;
  }
  
+ static void
+ convert_log_message(const StringInfo src, char **dst, int *dstlen)
+ {
+ 	if (*dst == NULL)
+ 	{
+ 		*dst = pg_server_to_platform(src->data, false);
+ 		*dstlen = (src->data == *dst ? src->len : strlen(*dst));
+ 	}
+ }
+ 
+ static void
+ free_log_messages(StringInfo buf, char *log)
+ {
+ 	if (log && log != buf->data)
+ 		pfree(log);
+ 	pfree(buf->data);
+ }
  
  /*
   * Write error report to server's log
*************** unpack_sql_state(int sql_state)
*** 1972,1978 ****
  static void
  send_message_to_server_log(ErrorData *edata)
  {
! 	StringInfoData buf;
  
  	initStringInfo(&buf);
  
--- 1991,1999 ----
  static void
  send_message_to_server_log(ErrorData *edata)
  {
! 	StringInfoData	buf;
! 	char		   *log_str;
! 	int				log_len;
  
  	initStringInfo(&buf);
  
*************** send_message_to_server_log(ErrorData *ed
*** 2067,2072 ****
--- 2088,2101 ----
  		appendStringInfoChar(&buf, '\n');
  	}
  
+ 	if (in_error_recursion_trouble())
+ 	{
+ 		log_str = buf.data;
+ 		log_len = buf.len;
+ 	}
+ 	else
+ 		log_str = NULL;
+ 
  #ifdef HAVE_SYSLOG
  	/* Write to syslog, if enabled */
  	if (Log_destination & LOG_DESTINATION_SYSLOG)
*************** send_message_to_server_log(ErrorData *ed
*** 2103,2109 ****
  				break;
  		}
  
! 		write_syslog(syslog_level, buf.data);
  	}
  #endif   /* HAVE_SYSLOG */
  
--- 2132,2139 ----
  				break;
  		}
  
! 		convert_log_message(&buf, &log_str, &log_len);
! 		write_syslog(syslog_level, log_str);
  	}
  #endif   /* HAVE_SYSLOG */
  
*************** send_message_to_server_log(ErrorData *ed
*** 2111,2117 ****
  	/* Write to eventlog, if enabled */
  	if (Log_destination & LOG_DESTINATION_EVENTLOG)
  	{
! 		write_eventlog(edata->elevel, buf.data);
  	}
  #endif   /* WIN32 */
  
--- 2141,2148 ----
  	/* Write to eventlog, if enabled */
  	if (Log_destination & LOG_DESTINATION_EVENTLOG)
  	{
! 		convert_log_message(&buf, &log_str, &log_len);
! 		write_eventlog(edata->elevel, log_str);
  	}
  #endif   /* WIN32 */
  
*************** send_message_to_server_log(ErrorData *ed
*** 2124,2130 ****
  		 * Otherwise, just do a vanilla write to stderr.
  		 */
  		if (redirection_done && !am_syslogger)
! 			write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_STDERR);
  #ifdef WIN32
  
  		/*
--- 2155,2177 ----
  		 * Otherwise, just do a vanilla write to stderr.
  		 */
  		if (redirection_done && !am_syslogger)
! 		{
! 			/* Convert message to log_encoding and send to syslogger. */
! 			int		database_encoding = GetDatabaseEncoding();
! 
! 			if (Log_encoding == database_encoding ||
! 				Log_encoding == PG_SQL_ASCII || database_encoding == PG_SQL_ASCII)
! 			{
! 				write_pipe_chunks(buf.data, buf.len, LOG_DESTINATION_STDERR);
! 			}
! 			else if (Log_encoding == GetPlatformEncoding())
! 			{
! 				convert_log_message(&buf, &log_str, &log_len);
! 				write_pipe_chunks(log_str, log_len, LOG_DESTINATION_STDERR);
! 			}
! 			else
! 				write_pipe_chunks_conv(buf.data, buf.len, LOG_DESTINATION_STDERR);
! 		}
  #ifdef WIN32
  
  		/*
*************** send_message_to_server_log(ErrorData *ed
*** 2135,2144 ****
  		 * because that's really a pipe to the syslogger process.
  		 */
  		else if (pgwin32_is_service())
! 			write_eventlog(edata->elevel, buf.data);
  #endif
  		else
! 			write(fileno(stderr), buf.data, buf.len);
  	}
  
  	/* If in the syslogger process, try to write messages direct to file */
--- 2182,2197 ----
  		 * because that's really a pipe to the syslogger process.
  		 */
  		else if (pgwin32_is_service())
! 		{
! 			convert_log_message(&buf, &log_str, &log_len);
! 			write_eventlog(edata->elevel, log_str);
! 		}
  #endif
  		else
! 		{
! 			convert_log_message(&buf, &log_str, &log_len);
! 			write(fileno(stderr), log_str, log_len);
! 		}
  	}
  
  	/* If in the syslogger process, try to write messages direct to file */
*************** send_message_to_server_log(ErrorData *ed
*** 2154,2160 ****
  			 * send CSV data if it's safe to do so (syslogger doesn't need the
  			 * pipe). First get back the space in the message buffer.
  			 */
! 			pfree(buf.data);
  			write_csvlog(edata);
  		}
  		else
--- 2207,2213 ----
  			 * send CSV data if it's safe to do so (syslogger doesn't need the
  			 * pipe). First get back the space in the message buffer.
  			 */
! 			free_log_messages(&buf, log_str);
  			write_csvlog(edata);
  		}
  		else
*************** send_message_to_server_log(ErrorData *ed
*** 2166,2179 ****
  				whereToSendOutput != DestDebug)
  			{
  				/* write message to stderr unless we just sent it above */
! 				write(fileno(stderr), buf.data, buf.len);
  			}
! 			pfree(buf.data);
  		}
  	}
  	else
  	{
! 		pfree(buf.data);
  	}
  }
  
--- 2219,2233 ----
  				whereToSendOutput != DestDebug)
  			{
  				/* write message to stderr unless we just sent it above */
! 				convert_log_message(&buf, &log_str, &log_len);
! 				write(fileno(stderr), log_str, log_len);
  			}
! 			free_log_messages(&buf, log_str);
  		}
  	}
  	else
  	{
! 		free_log_messages(&buf, log_str);
  	}
  }
  
*************** write_pipe_chunks(char *data, int len, i
*** 2210,2215 ****
--- 2264,2282 ----
  	write(fd, &p, PIPE_HEADER_SIZE + len);
  }
  
+ /* Convert message to log_encoding and send to syslogger. */
+ static void
+ write_pipe_chunks_conv(char *data, int len, int dest)
+ {
+ 	char *s = pg_server_to_log(data, false);
+ 	if (s == data)
+ 		write_pipe_chunks(data, len, dest);
+ 	else
+ 	{
+ 		write_pipe_chunks(s, strlen(s), dest);
+ 		pfree(s);
+ 	}
+ }
  
  /*
   * Append a text string to the error report being built for the client.
*************** err_sendstring(StringInfo buf, const cha
*** 2228,2234 ****
  	if (in_error_recursion_trouble())
  		pq_send_ascii_string(buf, str);
  	else
! 		pq_sendstring(buf, str);
  }
  
  /*
--- 2295,2314 ----
  	if (in_error_recursion_trouble())
  		pq_send_ascii_string(buf, str);
  	else
! 	{
! 		int			slen = strlen(str);
! 		char	   *p;
! 
! 		p = pg_server_to_client_throwable(str, slen, false);
! 		if (p != str)				/* actual conversion has been done? */
! 		{
! 			slen = strlen(p);
! 			appendBinaryStringInfo(buf, p, slen + 1);
! 			pfree(p);
! 		}
! 		else
! 			appendBinaryStringInfo(buf, str, slen + 1);
! 	}
  }
  
  /*
diff -cpr head/src/backend/utils/mb/mbutils.c server-side_encoding_issues/src/backend/utils/mb/mbutils.c
*** head/src/backend/utils/mb/mbutils.c	Thu Apr  9 11:56:48 2009
--- server-side_encoding_issues/src/backend/utils/mb/mbutils.c	Wed Apr 15 13:54:46 2009
*************** static List *ConvProcList = NIL;	/* List
*** 52,63 ****
--- 52,66 ----
   */
  static FmgrInfo *ToServerConvProc = NULL;
  static FmgrInfo *ToClientConvProc = NULL;
+ static FmgrInfo ToPlatformConvProc;
+ static FmgrInfo ToLogConvProc;
  
  /*
   * These variables track the currently selected FE and BE encodings.
   */
  static pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
  static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
+ static pg_enc2name *PlatformEncoding = NULL;
  
  /*
   * During backend startup we can't set client encoding because we (a)
*************** static int	pending_client_encoding = PG_
*** 71,78 ****
  
  /* Internal functions */
  static char *perform_default_encoding_conversion(const char *src,
! 									int len, bool is_client_to_server);
  static int	cliplen(const char *str, int len, int limit);
  
  
  /*
--- 74,84 ----
  
  /* Internal functions */
  static char *perform_default_encoding_conversion(const char *src,
! 	int len, int src_encoding, int dest_encoding, FmgrInfo *flinfo,
! 	bool throwable);
  static int	cliplen(const char *str, int len, int limit);
+ static Oid get_conversion_procid(int src_encoding, int dest_encoding);
+ static char *convert_to(const char *s, int encoding, FmgrInfo *cache, bool throwable);
  
  
  /*
*************** pg_do_encoding_conversion(unsigned char 
*** 302,330 ****
  	if (len <= 0)
  		return src;
  
! 	proc = FindDefaultConversionProc(src_encoding, dest_encoding);
  	if (!OidIsValid(proc))
- 	{
- 		ereport(LOG,
- 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
- 				 errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
- 						pg_encoding_to_char(src_encoding),
- 						pg_encoding_to_char(dest_encoding))));
  		return src;
- 	}
- 
- 	/*
- 	 * XXX we should avoid throwing errors in OidFunctionCall. Otherwise we
- 	 * are going into infinite loop!  So we have to make sure that the
- 	 * function exists before calling OidFunctionCall.
- 	 */
- 	if (!SearchSysCacheExists(PROCOID,
- 							  ObjectIdGetDatum(proc),
- 							  0, 0, 0))
- 	{
- 		elog(LOG, "cache lookup failed for function %u", proc);
- 		return src;
- 	}
  
  	/*
  	 * Allocate space for conversion result, being wary of integer overflow
--- 308,316 ----
  	if (len <= 0)
  		return src;
  
! 	proc = get_conversion_procid(src_encoding, dest_encoding);
  	if (!OidIsValid(proc))
  		return src;
  
  	/*
  	 * Allocate space for conversion result, being wary of integer overflow
*************** pg_do_encoding_conversion(unsigned char 
*** 347,352 ****
--- 333,372 ----
  	return result;
  }
  
+ static Oid
+ get_conversion_procid(int src_encoding, int dest_encoding)
+ {
+ 	Oid		proc;
+ 
+ 	Assert(IsTransactionState());
+ 
+ 	proc = FindDefaultConversionProc(src_encoding, dest_encoding);
+ 	if (!OidIsValid(proc))
+ 	{
+ 		ereport(LOG,
+ 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+ 				 errmsg("default conversion function for encoding \"%s\" to \"%s\" does not exist",
+ 						pg_encoding_to_char(src_encoding),
+ 						pg_encoding_to_char(dest_encoding))));
+ 		return InvalidOid;
+ 	}
+ 
+ 	/*
+ 	 * XXX we should avoid throwing errors in OidFunctionCall. Otherwise we
+ 	 * are going into infinite loop!  So we have to make sure that the
+ 	 * function exists before calling OidFunctionCall.
+ 	 */
+ 	if (!SearchSysCacheExists(PROCOID,
+ 							  ObjectIdGetDatum(proc),
+ 							  0, 0, 0))
+ 	{
+ 		elog(LOG, "cache lookup failed for function %u", proc);
+ 		return InvalidOid;
+ 	}
+ 
+ 	return proc;
+ }
+ 
  /*
   * Convert string using encoding_name. The source
   * encoding is the DB encoding.
*************** pg_client_to_server(const char *s, int l
*** 534,540 ****
  		return (char *) s;
  	}
  
! 	return perform_default_encoding_conversion(s, len, true);
  }
  
  /*
--- 554,562 ----
  		return (char *) s;
  	}
  
! 	return perform_default_encoding_conversion(s, len,
! 		ClientEncoding->encoding, DatabaseEncoding->encoding,
! 		ToServerConvProc, true);
  }
  
  /*
*************** pg_client_to_server(const char *s, int l
*** 543,548 ****
--- 565,576 ----
  char *
  pg_server_to_client(const char *s, int len)
  {
+ 	return pg_server_to_client_throwable(s, len, true);
+ }
+ 
+ char *
+ pg_server_to_client_throwable(const char *s, int len, bool throwable)
+ {
  	Assert(DatabaseEncoding);
  	Assert(ClientEncoding);
  
*************** pg_server_to_client(const char *s, int l
*** 554,560 ****
  		DatabaseEncoding->encoding == PG_SQL_ASCII)
  		return (char *) s;		/* assume data is valid */
  
! 	return perform_default_encoding_conversion(s, len, false);
  }
  
  /*
--- 582,642 ----
  		DatabaseEncoding->encoding == PG_SQL_ASCII)
  		return (char *) s;		/* assume data is valid */
  
! 	return perform_default_encoding_conversion(s, len,
! 		DatabaseEncoding->encoding, ClientEncoding->encoding,
! 		ToClientConvProc, throwable);
! }
! 
! char *
! pg_server_to_platform(const char *s, bool throwable)
! {
! 	return convert_to(s, GetPlatformEncoding(), &ToPlatformConvProc, throwable);
! }
! 
! char *
! pg_server_to_log(const char *s, bool throwable)
! {
! 	return convert_to(s, Log_encoding, &ToLogConvProc, throwable);
! }
! 
! static char *
! convert_to(const char *s, int encoding, FmgrInfo *cache, bool throwable)
! {
! 	int				src_encoding;
! 	int				len;
! 	unsigned char	ch;
! 
! 	Assert(DatabaseEncoding);
! 
! 	/* We cannot access system catalog without transaction. */
! 	if (!backend_startup_complete || !IsTransactionState())
! 		return (char *) s;
! 
! 	src_encoding = DatabaseEncoding->encoding;
! 	if (src_encoding == PG_SQL_ASCII)
! 		return (char *) s;
! 
! 	if (encoding == src_encoding || encoding == PG_SQL_ASCII)
! 		return (char *) s;		/* assume data is valid */
! 
! 	/* calc length and check highbit */
! 	ch = 0;
! 	for (len = 0; s[len]; len++)
! 		ch |= s[len];
! 	if (!IS_HIGHBIT_SET(ch))
! 		return (char *) s;		/* contains only ascii characters */
! 
! 	/* find conversion proc if not cached */
! 	if (cache->fn_addr == NULL)
! 	{
! 		Oid proc = get_conversion_procid(src_encoding, encoding);
! 		if (!OidIsValid(proc))
! 			return (char *) s;
! 		fmgr_info_cxt(proc, cache, TopMemoryContext);
! 	}
! 
! 	return perform_default_encoding_conversion(s, len,
! 		src_encoding, encoding, cache, throwable);
  }
  
  /*
*************** pg_server_to_client(const char *s, int l
*** 564,588 ****
   *	SetClientEncoding(), no conversion is performed.
   */
  static char *
! perform_default_encoding_conversion(const char *src, int len, bool is_client_to_server)
  {
! 	char	   *result;
! 	int			src_encoding,
! 				dest_encoding;
! 	FmgrInfo   *flinfo;
! 
! 	if (is_client_to_server)
! 	{
! 		src_encoding = ClientEncoding->encoding;
! 		dest_encoding = DatabaseEncoding->encoding;
! 		flinfo = ToServerConvProc;
! 	}
! 	else
! 	{
! 		src_encoding = DatabaseEncoding->encoding;
! 		dest_encoding = ClientEncoding->encoding;
! 		flinfo = ToClientConvProc;
! 	}
  
  	if (flinfo == NULL)
  		return (char *) src;
--- 646,659 ----
   *	SetClientEncoding(), no conversion is performed.
   */
  static char *
! perform_default_encoding_conversion(const char *src, int len,
! 	int src_encoding, int dest_encoding, FmgrInfo *flinfo, bool throwable)
  {
! 	char		   *result;
! 	int				i;
! 	MemoryContext	ccxt;
! 	MemoryContext	local_ErrorContext;
! 	MemoryContext	save_ErrorContext;
  
  	if (flinfo == NULL)
  		return (char *) src;
*************** perform_default_encoding_conversion(cons
*** 599,614 ****
  
  	result = palloc(len * MAX_CONVERSION_GROWTH + 1);
  
! 	FunctionCall5(flinfo,
! 				  Int32GetDatum(src_encoding),
! 				  Int32GetDatum(dest_encoding),
! 				  CStringGetDatum(src),
! 				  CStringGetDatum(result),
! 				  Int32GetDatum(len));
! 	return result;
! }
  
  
  
  #ifdef USE_WIDE_UPPER_LOWER
  
--- 670,779 ----
  
  	result = palloc(len * MAX_CONVERSION_GROWTH + 1);
  
! 	if (throwable)
! 	{
! 		FunctionCall5(flinfo,
! 					  Int32GetDatum(src_encoding),
! 					  Int32GetDatum(dest_encoding),
! 					  CStringGetDatum(src),
! 					  CStringGetDatum(result),
! 					  Int32GetDatum(len));
! 		return result;
! 	}
  
+ 	/*
+ 	 * TODO: better implementation. To use PG_TRY and PG_CATCH are far from
+ 	 * ideal for no-throw conversion. We'd better to rewrite conversion procs
+ 	 * to take an additional argument whether it should throw or not.
+ 	 */
+ 	ccxt = CurrentMemoryContext;
+ 	local_ErrorContext = AllocSetContextCreate(CurrentMemoryContext,
+ 										 "ErrorContext for conversion",
+ 										 8 * 1024,
+ 										 8 * 1024,
+ 										 8 * 1024);
+ 	save_ErrorContext = ErrorContext;
+ 
+ 	ErrorContext = local_ErrorContext;
+ 	i = 0;
+ 	PG_TRY();
+ 	{
+ 		FunctionCall5(flinfo,
+ 					  Int32GetDatum(src_encoding),
+ 					  Int32GetDatum(dest_encoding),
+ 					  CStringGetDatum(src),
+ 					  CStringGetDatum(result),
+ 					  Int32GetDatum(len));
+ 		i = 1;
+ 	}
+ 	PG_CATCH();
+ 	{
+ 		/* TODO: better implementation */
+ 		MemoryContextSwitchTo(ccxt);
+ 		MemoryContextResetAndDeleteChildren(local_ErrorContext);
+ 		i = 0;
+ 	}
+ 	PG_END_TRY();
+ 
+ 	if (i)
+ 	{
+ 		ErrorContext = save_ErrorContext;
+ 		MemoryContextDelete(local_ErrorContext);
+ 		return result;	/* succeeded to convert without error */
+ 	}
+ 
+ 	/*
+ 	 * The src string contains some unconvertable characters.
+ 	 * Convert the src character by character, or '?' for unconvertable one.
+ 	 */
+ 	i = 0;
+ 	while (*src)
+ 	{
+ 		if (!IS_HIGHBIT_SET(*src))
+ 		{
+ 			result[i] = *src;
+ 			src++;
+ 			i++;
+ 		}
+ 		else
+ 		{
+ 			int	clen = pg_mblen(src);
+ 
+ 			PG_TRY();
+ 			{
+ 				char	dst[4 /*(clen)*/ * MAX_CONVERSION_GROWTH + 1];
+ 				int		dstlen;
+ 
+ 				FunctionCall5(flinfo,
+ 							  Int32GetDatum(src_encoding),
+ 							  Int32GetDatum(dest_encoding),
+ 							  CStringGetDatum(src),
+ 							  CStringGetDatum(dst),
+ 							  Int32GetDatum(clen));
+ 
+ 				dstlen = strlen(dst);
+ 				memcpy(result + i, dst, dstlen);
+ 				i += dstlen;
+ 			}
+ 			PG_CATCH();
+ 			{
+ 				/* TODO: better implementation */
+ 				MemoryContextSwitchTo(ccxt);
+ 				MemoryContextResetAndDeleteChildren(local_ErrorContext);
+ 				result[i] = '?';
+ 				i++;
+ 			}
+ 			PG_END_TRY();
+ 
+ 			src += clen;
+ 		}
+ 	}
+ 	result[i] = 0;	/* terminate */
  
+ 	ErrorContext = save_ErrorContext;
+ 	MemoryContextDelete(local_ErrorContext);
+ 	return result;
+ }
  
  #ifdef USE_WIDE_UPPER_LOWER
  
*************** pg_client_encoding(PG_FUNCTION_ARGS)
*** 1009,1011 ****
--- 1174,1184 ----
  	Assert(ClientEncoding);
  	return DirectFunctionCall1(namein, CStringGetDatum(ClientEncoding->name));
  }
+ 
+ int
+ GetPlatformEncoding(void)
+ {
+ 	if (PlatformEncoding == NULL)
+ 		PlatformEncoding = &pg_enc2name_tbl[pg_get_encoding_from_locale("")];
+ 	return PlatformEncoding->encoding;
+ }
diff -cpr head/src/backend/utils/misc/guc.c server-side_encoding_issues/src/backend/utils/misc/guc.c
*** head/src/backend/utils/misc/guc.c	Thu Apr  9 11:56:48 2009
--- server-side_encoding_issues/src/backend/utils/misc/guc.c	Wed Apr 15 13:54:46 2009
*************** static const char *assign_pgstat_temp_di
*** 172,177 ****
--- 172,178 ----
  static char *config_enum_get_options(struct config_enum *record, 
  									 const char *prefix, const char *suffix,
  									 const char *separator);
+ static const char *assign_log_encoding(const char *value, bool doit, GucSource source);
  
  
  /*
*************** static char *server_version_string;
*** 403,408 ****
--- 404,410 ----
  static int	server_version_num;
  static char *timezone_string;
  static char *log_timezone_string;
+ static char *log_encoding_string;
  static char *timezone_abbreviations_string;
  static char *XactIsoLevel_string;
  static char *data_directory;
*************** static struct config_string ConfigureNam
*** 2352,2357 ****
--- 2354,2368 ----
  		&Log_filename,
  		"postgresql-%Y-%m-%d_%H%M%S.log", NULL, NULL
  	},
+ 	{
+ 		{"log_encoding", PGC_SIGHUP, LOGGING_WHERE,
+ 			gettext_noop("Sets the log files' character set encoding."),
+ 			NULL,
+ 			GUC_SUPERUSER_ONLY
+ 		},
+ 		&log_encoding_string,
+ 		"SQL_ASCII", assign_log_encoding, NULL
+ 	},
  
  #ifdef HAVE_SYSLOG
  	{
*************** assign_pgstat_temp_directory(const char 
*** 7633,7636 ****
--- 7644,7661 ----
  	return newval;
  }
  
+ static const char *
+ assign_log_encoding(const char *value, bool doit, GucSource source)
+ {
+ 	int			encoding;
+ 
+ 	encoding = pg_valid_client_encoding(value);
+ 	if (encoding < 0)
+ 		return NULL;
+ 
+ 	if (doit)
+ 		Log_encoding = encoding;
+ 	return value;
+ }
+ 
  #include "guc-file.c"
diff -cpr head/src/backend/utils/misc/postgresql.conf.sample server-side_encoding_issues/src/backend/utils/misc/postgresql.conf.sample
*** head/src/backend/utils/misc/postgresql.conf.sample	Thu Apr  9 11:56:48 2009
--- server-side_encoding_issues/src/backend/utils/misc/postgresql.conf.sample	Wed Apr 15 13:54:46 2009
***************
*** 257,262 ****
--- 257,263 ----
  #log_rotation_size = 10MB		# Automatic rotation of logfiles will 
  					# happen after that much log output.
  					# 0 disables.
+ #log_encoding = sql_ascii		# actually, defaults to database encoding
  
  # These are relevant when logging to syslog:
  #syslog_facility = 'LOCAL0'
diff -cpr head/src/bin/initdb/initdb.c server-side_encoding_issues/src/bin/initdb/initdb.c
*** head/src/bin/initdb/initdb.c	Mon Apr  6 10:02:58 2009
--- server-side_encoding_issues/src/bin/initdb/initdb.c	Wed Apr 15 13:54:46 2009
*************** static char *share_path = NULL;
*** 70,76 ****
  
  /* values to be obtained from arguments */
  static char *pg_data = "";
! static char *encoding = "";
  static char *locale = "";
  static char *lc_collate = "";
  static char *lc_ctype = "";
--- 70,76 ----
  
  /* values to be obtained from arguments */
  static char *pg_data = "";
! static const char *encoding = "";
  static char *locale = "";
  static char *lc_collate = "";
  static char *lc_ctype = "";
*************** static FILE *popen_check(const char *com
*** 155,161 ****
  static int	mkdir_p(char *path, mode_t omode);
  static void exit_nicely(void);
  static char *get_id(void);
! static char *get_encoding_id(char *encoding_name);
  static char *get_short_version(void);
  static int	check_data_dir(char *dir);
  static bool mkdatadir(const char *subdir);
--- 155,161 ----
  static int	mkdir_p(char *path, mode_t omode);
  static void exit_nicely(void);
  static char *get_id(void);
! static char *get_encoding_id(const char *encoding_name);
  static char *get_short_version(void);
  static int	check_data_dir(char *dir);
  static bool mkdatadir(const char *subdir);
*************** encodingid_to_string(int enc)
*** 708,714 ****
   * get the encoding id for a given encoding name
   */
  static char *
! get_encoding_id(char *encoding_name)
  {
  	int			enc;
  
--- 708,714 ----
   * get the encoding id for a given encoding name
   */
  static char *
! get_encoding_id(const char *encoding_name)
  {
  	int			enc;
  
*************** setup_config(void)
*** 1205,1210 ****
--- 1205,1214 ----
  						 "#default_text_search_config = 'pg_catalog.simple'",
  							  repltok);
  
+ 	snprintf(repltok, sizeof(repltok), "log_encoding = '%s'",
+ 			 escape_quotes(encoding));
+ 	conflines = replace_token(conflines, "#log_encoding = sql_ascii", repltok);
+ 
  	snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
  
  	writefile(path, conflines);
*************** main(int argc, char *argv[])
*** 2922,2927 ****
--- 2926,2933 ----
  		!check_locale_encoding(lc_collate, user_enc))
  		exit(1); /* check_locale_encoding printed the error */
  
+ 	encoding = pg_encoding_to_char(user_enc);
+ 
  	if (strlen(default_text_search_config) == 0)
  	{
  		default_text_search_config = find_matching_ts_config(lc_ctype);
diff -cpr head/src/include/mb/pg_wchar.h server-side_encoding_issues/src/include/mb/pg_wchar.h
*** head/src/include/mb/pg_wchar.h	Thu Apr  9 11:56:48 2009
--- server-side_encoding_issues/src/include/mb/pg_wchar.h	Wed Apr 15 13:54:46 2009
*************** extern const char *pg_get_client_encodin
*** 391,396 ****
--- 391,397 ----
  extern void SetDatabaseEncoding(int encoding);
  extern int	GetDatabaseEncoding(void);
  extern const char *GetDatabaseEncodingName(void);
+ extern int	GetPlatformEncoding(void);
  extern void pg_bind_textdomain_codeset(const char *domainname);
  
  extern int	pg_valid_client_encoding(const char *name);
*************** extern unsigned char *pg_do_encoding_con
*** 404,409 ****
--- 405,414 ----
  
  extern char *pg_client_to_server(const char *s, int len);
  extern char *pg_server_to_client(const char *s, int len);
+ extern char *pg_server_to_client_throwable(const char *s, int len,
+ 										   bool throwable);
+ extern char *pg_server_to_platform(const char *s, bool throwable);
+ extern char *pg_server_to_log(const char *s, bool throwable);
  
  extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc);
  extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc);
diff -cpr head/src/include/utils/elog.h server-side_encoding_issues/src/include/utils/elog.h
*** head/src/include/utils/elog.h	Wed Jan  7 00:37:38 2009
--- server-side_encoding_issues/src/include/utils/elog.h	Wed Apr 15 13:54:46 2009
*************** typedef enum
*** 315,320 ****
--- 315,321 ----
  extern int	Log_error_verbosity;
  extern char *Log_line_prefix;
  extern int	Log_destination;
+ extern int	Log_encoding;
  
  /* Log destination bitmap */
  #define LOG_DESTINATION_STDERR	 1
diff -cpr head/src/port/chklocale.c server-side_encoding_issues/src/port/chklocale.c
*** head/src/port/chklocale.c	Fri Feb 13 09:58:01 2009
--- server-side_encoding_issues/src/port/chklocale.c	Wed Apr 15 13:54:46 2009
*************** static const struct encoding_match encod
*** 73,78 ****
--- 73,79 ----
  	{PG_UTF8, "UTF-8"},
  	{PG_UTF8, "utf8"},
  	{PG_UTF8, "CP65001"},
+ 	{PG_UTF8, "ANSI_X3.4-1968"},
  
  	{PG_LATIN1, "ISO-8859-1"},
  	{PG_LATIN1, "ISO8859-1"},
