diff -cprN head/src/backend/utils/error/elog.c work/src/backend/utils/error/elog.c *** head/src/backend/utils/error/elog.c 2009-07-04 04:14:25.000000000 +0900 --- work/src/backend/utils/error/elog.c 2009-10-13 10:11:34.310337321 +0900 *************** static int syslog_facility = LOG_LOCAL0; *** 111,118 **** static void write_syslog(int level, const char *line); #endif #ifdef WIN32 ! static void write_eventlog(int level, const char *line); #endif /* We provide a small stack of ErrorData records for re-entrant cases */ --- 111,120 ---- static void write_syslog(int level, const char *line); #endif + static void write_console(const char *line, int len); + #ifdef WIN32 ! static void write_eventlog(int level, const char *line, int len); #endif /* We provide a small stack of ErrorData records for re-entrant cases */ *************** write_syslog(int level, const char *line *** 1567,1576 **** * Write a message line to the windows event log */ static void ! write_eventlog(int level, const char *line) { ! int eventlevel = EVENTLOG_ERROR_TYPE; ! static HANDLE evtHandle = INVALID_HANDLE_VALUE; if (evtHandle == INVALID_HANDLE_VALUE) { --- 1569,1579 ---- * Write a message line to the windows event log */ static void ! write_eventlog(int level, const char *line, int len) { ! WCHAR *utf16; ! int eventlevel = EVENTLOG_ERROR_TYPE; ! static HANDLE evtHandle = INVALID_HANDLE_VALUE; if (evtHandle == INVALID_HANDLE_VALUE) { *************** write_eventlog(int level, const char *li *** 1606,1613 **** break; } ! ReportEvent(evtHandle, eventlevel, 0, 0, /* All events are Id 0 */ --- 1609,1637 ---- break; } + /* + * Convert message to UTF16 text and write it with ReportEventW, + * but fall-back into ReportEventA if conversion failed. + */ + if (!in_error_recursion_trouble() && + GetDatabaseEncoding() != GetPlatformEncoding() && + (utf16 = pgwin32_toUTF16(line, len, NULL)) != NULL) + { + ReportEventW(evtHandle, + eventlevel, + 0, + 0, /* All events are Id 0 */ + NULL, + 1, + 0, + (LPCWSTR *) &utf16, + NULL); ! pfree(utf16); ! } ! else ! { ! ReportEventA(evtHandle, eventlevel, 0, 0, /* All events are Id 0 */ *************** write_eventlog(int level, const char *li *** 1616,1624 **** --- 1640,1690 ---- 0, &line, NULL); + } } + #endif /* WIN32 */ + static void + write_console(const char *line, int len) + { + #ifdef WIN32 + if (!in_error_recursion_trouble() && + GetDatabaseEncoding() != GetPlatformEncoding()) + { + static bool redirected = false; + WCHAR *utf16; + int utf16len; + + if (!redirected && + (utf16 = pgwin32_toUTF16(line, len, &utf16len)) != NULL) + { + HANDLE stdHandle; + DWORD written; + + stdHandle = GetStdHandle(STD_ERROR_HANDLE); + if (WriteConsoleW(stdHandle, utf16, utf16len, &written, NULL)) + { + pfree(utf16); + return; + } + + /* WriteConsoleW always fails if stderr is redirected. */ + pfree(utf16); + redirected = true; + } + } + #else + /* + * Conversion on non-win32 platform is not implemented yet. + * It requires non-throw version of pg_do_encoding_conversion(), + * that converts unconvertable characters to '?' without errors. + */ + #endif + + write(fileno(stderr), line, len); + } + /* * setup formatted_log_time, for consistent times between CSV and regular logs */ *************** send_message_to_server_log(ErrorData *ed *** 2206,2212 **** /* Write to eventlog, if enabled */ if (Log_destination & LOG_DESTINATION_EVENTLOG) { ! write_eventlog(edata->elevel, buf.data); } #endif /* WIN32 */ --- 2272,2278 ---- /* Write to eventlog, if enabled */ if (Log_destination & LOG_DESTINATION_EVENTLOG) { ! write_eventlog(edata->elevel, buf.data, buf.len); } #endif /* WIN32 */ *************** send_message_to_server_log(ErrorData *ed *** 2230,2239 **** * 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 */ --- 2296,2305 ---- * because that's really a pipe to the syslogger process. */ else if (pgwin32_is_service()) ! write_eventlog(edata->elevel, buf.data, buf.len); #endif else ! write_console(buf.data, buf.len); } /* If in the syslogger process, try to write messages direct to file */ *************** send_message_to_server_log(ErrorData *ed *** 2256,2267 **** { const char *msg = _("Not safe to send CSV data\n"); ! write(fileno(stderr), msg, strlen(msg)); if (!(Log_destination & LOG_DESTINATION_STDERR) && whereToSendOutput != DestDebug) { /* write message to stderr unless we just sent it above */ ! write(fileno(stderr), buf.data, buf.len); } pfree(buf.data); } --- 2322,2333 ---- { const char *msg = _("Not safe to send CSV data\n"); ! write_console(msg, strlen(msg)); if (!(Log_destination & LOG_DESTINATION_STDERR) && whereToSendOutput != DestDebug) { /* write message to stderr unless we just sent it above */ ! write_console(buf.data, buf.len); } pfree(buf.data); } *************** void *** 2642,2647 **** --- 2708,2716 ---- write_stderr(const char *fmt,...) { va_list ap; + #ifdef WIN32 + char errbuf[2048]; /* Arbitrary size? */ + #endif fmt = _(fmt); *************** write_stderr(const char *fmt,...) *** 2651,2656 **** --- 2720,2726 ---- vfprintf(stderr, fmt, ap); fflush(stderr); #else + vsnprintf(errbuf, sizeof(errbuf), fmt, ap); /* * On Win32, we print to stderr if running on a console, or write to *************** write_stderr(const char *fmt,...) *** 2658,2673 **** */ if (pgwin32_is_service()) /* Running as a service */ { ! char errbuf[2048]; /* Arbitrary size? */ ! ! vsnprintf(errbuf, sizeof(errbuf), fmt, ap); ! ! write_eventlog(ERROR, errbuf); } else { /* Not running as service, write to stderr */ ! vfprintf(stderr, fmt, ap); fflush(stderr); } #endif --- 2728,2739 ---- */ if (pgwin32_is_service()) /* Running as a service */ { ! write_eventlog(ERROR, errbuf, strlen(errbuf)); } else { /* Not running as service, write to stderr */ ! write_console(errbuf, strlen(errbuf)); fflush(stderr); } #endif diff -cprN head/src/backend/utils/mb/encnames.c work/src/backend/utils/mb/encnames.c *** head/src/backend/utils/mb/encnames.c 2009-04-24 17:43:50.000000000 +0900 --- work/src/backend/utils/mb/encnames.c 2009-10-13 10:08:42.641335971 +0900 *************** sizeof(pg_encname_tbl) / sizeof(pg_encna *** 300,433 **** * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) * ---------- */ pg_enc2name pg_enc2name_tbl[] = { ! { ! "SQL_ASCII", PG_SQL_ASCII ! }, ! { ! "EUC_JP", PG_EUC_JP ! }, ! { ! "EUC_CN", PG_EUC_CN ! }, ! { ! "EUC_KR", PG_EUC_KR ! }, ! { ! "EUC_TW", PG_EUC_TW ! }, ! { ! "EUC_JIS_2004", PG_EUC_JIS_2004 ! }, ! { ! "UTF8", PG_UTF8 ! }, ! { ! "MULE_INTERNAL", PG_MULE_INTERNAL ! }, ! { ! "LATIN1", PG_LATIN1 ! }, ! { ! "LATIN2", PG_LATIN2 ! }, ! { ! "LATIN3", PG_LATIN3 ! }, ! { ! "LATIN4", PG_LATIN4 ! }, ! { ! "LATIN5", PG_LATIN5 ! }, ! { ! "LATIN6", PG_LATIN6 ! }, ! { ! "LATIN7", PG_LATIN7 ! }, ! { ! "LATIN8", PG_LATIN8 ! }, ! { ! "LATIN9", PG_LATIN9 ! }, ! { ! "LATIN10", PG_LATIN10 ! }, ! { ! "WIN1256", PG_WIN1256 ! }, ! { ! "WIN1258", PG_WIN1258 ! }, ! { ! "WIN866", PG_WIN866 ! }, ! { ! "WIN874", PG_WIN874 ! }, ! { ! "KOI8R", PG_KOI8R ! }, ! { ! "WIN1251", PG_WIN1251 ! }, ! { ! "WIN1252", PG_WIN1252 ! }, ! { ! "ISO_8859_5", PG_ISO_8859_5 ! }, ! { ! "ISO_8859_6", PG_ISO_8859_6 ! }, ! { ! "ISO_8859_7", PG_ISO_8859_7 ! }, ! { ! "ISO_8859_8", PG_ISO_8859_8 ! }, ! { ! "WIN1250", PG_WIN1250 ! }, ! { ! "WIN1253", PG_WIN1253 ! }, ! { ! "WIN1254", PG_WIN1254 ! }, ! { ! "WIN1255", PG_WIN1255 ! }, ! { ! "WIN1257", PG_WIN1257 ! }, ! { ! "KOI8U", PG_KOI8U ! }, ! { ! "SJIS", PG_SJIS ! }, ! { ! "BIG5", PG_BIG5 ! }, ! { ! "GBK", PG_GBK ! }, ! { ! "UHC", PG_UHC ! }, ! { ! "GB18030", PG_GB18030 ! }, ! { ! "JOHAB", PG_JOHAB ! }, ! { ! "SHIFT_JIS_2004", PG_SHIFT_JIS_2004 ! } }; /* ---------- --- 300,354 ---- * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) * ---------- */ + #ifdef WIN32 + #define def_enc2name(name, codepage) { #name, PG_##name, codepage } + #else + #define def_enc2name(name, codepage) { #name, PG_##name } + #endif pg_enc2name pg_enc2name_tbl[] = { ! def_enc2name(SQL_ASCII, 0), ! def_enc2name(EUC_JP, 20932), ! def_enc2name(EUC_CN, 20936), ! def_enc2name(EUC_KR, 51949), ! def_enc2name(EUC_TW, 0), ! def_enc2name(EUC_JIS_2004, 20932), ! def_enc2name(UTF8, 65001), ! def_enc2name(MULE_INTERNAL, 0), ! def_enc2name(LATIN1, 28591), ! def_enc2name(LATIN2, 28592), ! def_enc2name(LATIN3, 28593), ! def_enc2name(LATIN4, 28594), ! def_enc2name(LATIN5, 28599), ! def_enc2name(LATIN6, 0), ! def_enc2name(LATIN7, 0), ! def_enc2name(LATIN8, 0), ! def_enc2name(LATIN9, 28605), ! def_enc2name(LATIN10, 0), ! def_enc2name(WIN1256, 1256), ! def_enc2name(WIN1258, 1258), ! def_enc2name(WIN866, 866), ! def_enc2name(WIN874, 874), ! def_enc2name(KOI8R, 20866), ! def_enc2name(WIN1251, 1251), ! def_enc2name(WIN1252, 1252), ! def_enc2name(ISO_8859_5, 28595), ! def_enc2name(ISO_8859_6, 28596), ! def_enc2name(ISO_8859_7, 28597), ! def_enc2name(ISO_8859_8, 28598), ! def_enc2name(WIN1250, 1250), ! def_enc2name(WIN1253, 1253), ! def_enc2name(WIN1254, 1254), ! def_enc2name(WIN1255, 1255), ! def_enc2name(WIN1257, 1257), ! def_enc2name(KOI8U, 21866), ! def_enc2name(SJIS, 932), ! def_enc2name(BIG5, 950), ! def_enc2name(GBK, 936), ! def_enc2name(UHC, 0), ! def_enc2name(GB18030, 54936), ! def_enc2name(JOHAB, 0), ! def_enc2name(SHIFT_JIS_2004, 932) }; /* ---------- diff -cprN head/src/backend/utils/mb/mbutils.c work/src/backend/utils/mb/mbutils.c *** head/src/backend/utils/mb/mbutils.c 2009-07-08 04:28:56.000000000 +0900 --- work/src/backend/utils/mb/mbutils.c 2009-10-13 10:08:42.642363445 +0900 *************** static FmgrInfo *ToClientConvProc = NULL *** 58,63 **** --- 58,64 ---- */ 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) *************** pg_client_encoding(PG_FUNCTION_ARGS) *** 978,980 **** --- 979,1044 ---- 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; + } + + #ifdef WIN32 + + /* + * Result is palloc'ed null-terminated utf16 string. The character length + * is also passed to utf16len if not null. Returns NULL iff failed. + */ + WCHAR * + pgwin32_toUTF16(const char *str, int len, int *utf16len) + { + WCHAR *utf16; + int dstlen; + UINT codepage; + + codepage = pg_enc2name_tbl[GetDatabaseEncoding()].codepage; + + /* + * Use MultiByteToWideChar directly if there is a corresponding codepage, + * or double conversion through UTF8. + */ + if (codepage != 0) + { + utf16 = (WCHAR *) palloc(sizeof(WCHAR) * (len + 1)); + dstlen = MultiByteToWideChar(codepage, 0, str, len, utf16, len); + utf16[dstlen] = L'\0'; + } + else + { + char *utf8; + + utf8 = (char *) pg_do_encoding_conversion((unsigned char *) str, + len, GetDatabaseEncoding(), PG_UTF8); + if (utf8 != str) + len = strlen(utf8); + + utf16 = (WCHAR *) palloc(sizeof(WCHAR) * (len + 1)); + dstlen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, len); + utf16[dstlen] = L'\0'; + + if (utf8 != str) + pfree(utf8); + } + + if (dstlen == 0 && len > 0) + { + pfree(utf16); + return NULL; /* error */ + } + + if (utf16len) + *utf16len = dstlen; + return utf16; + } + + #endif diff -cprN head/src/include/mb/pg_wchar.h work/src/include/mb/pg_wchar.h *** head/src/include/mb/pg_wchar.h 2009-06-11 23:49:11.000000000 +0900 --- work/src/include/mb/pg_wchar.h 2009-10-13 10:08:42.642363445 +0900 *************** typedef struct pg_enc2name *** 257,262 **** --- 257,265 ---- { char *name; pg_enc encoding; + #ifdef WIN32 + unsigned codepage; /* codepage for WIN32 */ + #endif } pg_enc2name; extern pg_enc2name pg_enc2name_tbl[]; *************** extern const char *pg_get_client_encodin *** 402,407 **** --- 405,411 ---- 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 void mic2latin_with_table(const u *** 458,461 **** --- 462,469 ---- extern bool pg_utf8_islegal(const unsigned char *source, int length); + #ifdef WIN32 + extern WCHAR *pgwin32_toUTF16(const char *str, int len, int *utf16len); + #endif + #endif /* PG_WCHAR_H */