diff -cprN head/src/backend/utils/error/elog.c eventlog/src/backend/utils/error/elog.c *** head/src/backend/utils/error/elog.c 2009-07-04 04:14:25.000000000 +0900 --- eventlog/src/backend/utils/error/elog.c 2009-09-15 12:31:24.555451172 +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,1573 **** * 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; --- 1569,1575 ---- * Write a message line to the windows event log */ static void ! write_eventlog(int level, const char *line, int len) { int eventlevel = EVENTLOG_ERROR_TYPE; static HANDLE evtHandle = INVALID_HANDLE_VALUE; *************** write_eventlog(int level, const char *li *** 1606,1613 **** break; } ! ! ReportEvent(evtHandle, eventlevel, 0, 0, /* All events are Id 0 */ --- 1608,1616 ---- break; } ! if (GetDatabaseEncoding() == GetPlatformEncoding()) ! { ! ReportEventA(evtHandle, eventlevel, 0, 0, /* All events are Id 0 */ *************** write_eventlog(int level, const char *li *** 1616,1624 **** --- 1619,1685 ---- 0, &line, NULL); + } + else + { + WCHAR *utf16; + int utf16len; + + utf16 = pgwin32_toUTF16(line, len, &utf16len); + ReportEventW(evtHandle, + eventlevel, + 0, + 0, /* All events are Id 0 */ + NULL, + 1, + 0, + (LPCWSTR *) &utf16, + NULL); + + pfree(utf16); + } } + #endif /* WIN32 */ + static void + write_console(const char *line, int len) + { + if (GetDatabaseEncoding() != GetPlatformEncoding()) + { + #ifdef WIN32 + static bool redirected = false; + + if (!redirected) + { + WCHAR *utf16; + int utf16len; + HANDLE stderrHandle; + DWORD written; + + utf16 = pgwin32_toUTF16(line, len, &utf16len); + stderrHandle = GetStdHandle(STD_ERROR_HANDLE); + if (WriteConsoleW(stderrHandle, utf16, utf16len, &written, NULL)) + { + pfree(utf16); + return; + } + + pfree(utf16); + redirected = true; /* stderr might be redirected */ + } + #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 */ --- 2267,2273 ---- /* 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 */ --- 2291,2300 ---- * 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); } --- 2317,2328 ---- { 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 **** --- 2703,2711 ---- 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 **** --- 2715,2721 ---- 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 --- 2723,2734 ---- */ 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/mbutils.c eventlog/src/backend/utils/mb/mbutils.c *** head/src/backend/utils/mb/mbutils.c 2009-07-08 04:28:56.000000000 +0900 --- eventlog/src/backend/utils/mb/mbutils.c 2009-09-15 12:31:24.556451161 +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,1083 ---- 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 + + static const UINT encoding_to_codepage[] = + { + 0, /* PG_SQL_ASCII */ + 20932, /* PG_EUC_JP */ + 20936, /* PG_EUC_CN */ + 51949, /* PG_EUC_KR */ + 0, /* PG_EUC_TW */ + 20932, /* PG_EUC_JIS_2004 */ + CP_UTF8, /* PG_UTF8 */ + 0, /* PG_MULE_INTERNAL */ + 28591, /* PG_LATIN1 */ + 28592, /* PG_LATIN2 */ + 28593, /* PG_LATIN3 */ + 28594, /* PG_LATIN4 */ + 28599, /* PG_LATIN5 */ + 0, /* PG_LATIN6 */ + 0, /* PG_LATIN7 */ + 0, /* PG_LATIN8 */ + 28605, /* PG_LATIN9 */ + 0, /* PG_LATIN10 */ + 1256, /* PG_WIN1256 */ + 1258, /* PG_WIN1258 */ + 866, /* PG_WIN866 */ + 874, /* PG_WIN874 */ + 20866, /* PG_KOI8R */ + 1251, /* PG_WIN1251 */ + 1252, /* PG_WIN1252 */ + 28595, /* PG_ISO_8859_5 */ + 28596, /* PG_ISO_8859_6 */ + 28597, /* PG_ISO_8859_7 */ + 28598, /* PG_ISO_8859_8 */ + 1250, /* PG_WIN1250 */ + 1253, /* PG_WIN1253 */ + 1254, /* PG_WIN1254 */ + 1255, /* PG_WIN1255 */ + 1257, /* PG_WIN1257 */ + 21866, /* PG_KOI8U */ + 932, /* PG_SJIS */ + 950, /* PG_BIG5 */ + 936, /* PG_GBK */ + 0, /* PG_UHC */ + 54936, /* PG_GB18030 */ + 0, /* PG_JOHAB */ + 932 /* PG_SHIFT_JIS_2004 */ + }; + + /* + * Result is palloc'ed null-terminated utf16 string. The character length + * is also passed to utf16len if not null. + */ + WCHAR * + pgwin32_toUTF16(const char *str, int len, int *utf16len) + { + WCHAR *utf16; + UINT codepage; + + codepage = encoding_to_codepage[GetDatabaseEncoding()]; + + /* + * Use MultiByteToWideChar directly if there is a corresponding codepage, + * or double conversion through UTF8. + */ + if (codepage != 0) + { + utf16 = (WCHAR *) palloc(sizeof(WCHAR) * (len + 1)); + len = MultiByteToWideChar(codepage, 0, str, len, utf16, len); + utf16[len] = 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)); + len = MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, len); + utf16[len] = L'\0'; + + if (utf8 != str) + pfree(utf8); + } + + if (utf16len) + *utf16len = len; + return utf16; + } + + #endif diff -cprN head/src/include/mb/pg_wchar.h eventlog/src/include/mb/pg_wchar.h *** head/src/include/mb/pg_wchar.h 2009-06-11 23:49:11.000000000 +0900 --- eventlog/src/include/mb/pg_wchar.h 2009-09-15 12:31:24.556451161 +0900 *************** extern const char *pg_get_client_encodin *** 402,407 **** --- 402,408 ---- 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 **** --- 459,466 ---- 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 */ diff -cprN head/src/port/open.c eventlog/src/port/open.c *** head/src/port/open.c 2009-06-11 23:49:15.000000000 +0900 --- eventlog/src/port/open.c 2009-09-15 12:31:24.556451161 +0900 *************** *** 23,28 **** --- 23,31 ---- #include #include + #ifndef FRONTEND + #include "mb/pg_wchar.h" + #endif static int openFlagsToCreateFileFlags(int openFlags) *************** pgwin32_open(const char *fileName, int f *** 65,70 **** --- 68,78 ---- HANDLE h = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES sa; int loops = 0; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; + WCHAR *wFileName = NULL; /* Check that we can handle the request */ assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND | *************** pgwin32_open(const char *fileName, int f *** 72,97 **** _O_SHORT_LIVED | O_DSYNC | O_DIRECT | (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags); - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - while ((h = CreateFile(fileName, /* cannot use O_RDONLY, as it == 0 */ ! (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : ! ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ), /* These flags allow concurrent rename/unlink */ ! (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), ! &sa, ! openFlagsToCreateFileFlags(fileFlags), ! FILE_ATTRIBUTE_NORMAL | ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) | ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) | ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) | ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) | ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) | ! ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0), ! NULL)) == INVALID_HANDLE_VALUE) { /* * Sharing violation or locking error can indicate antivirus, backup --- 80,126 ---- _O_SHORT_LIVED | O_DSYNC | O_DIRECT | (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags); /* cannot use O_RDONLY, as it == 0 */ ! dwDesiredAccess = (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : ! ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ); /* These flags allow concurrent rename/unlink */ ! dwShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE); ! dwCreationDisposition = openFlagsToCreateFileFlags(fileFlags); ! dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) | ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) | ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) | ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) | ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) | ! ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0); ! ! sa.nLength = sizeof(sa); ! sa.bInheritHandle = TRUE; ! sa.lpSecurityDescriptor = NULL; ! ! #ifndef FRONTEND ! /* ! * Use wide-character file name only if the database encoding doesn't match ! * to the platform encoding and the path contains any multi-byte characters. ! */ ! if (GetDatabaseEncoding() != GetPlatformEncoding()) ! { ! int len; ! bool hasMBChar = false; ! ! for (len = 0; fileName[len]; len++) ! hasMBChar |= IS_HIGHBIT_SET(fileName[len]); ! if (hasMBChar) ! wFileName = pgwin32_toUTF16(fileName, len, NULL); ! } ! #endif ! ! while ((h = (wFileName != NULL ! ? CreateFileW(wFileName, dwDesiredAccess, dwShareMode, &sa, ! dwCreationDisposition, dwFlagsAndAttributes, NULL) ! : CreateFileA(fileName, dwDesiredAccess, dwShareMode, &sa, ! dwCreationDisposition, dwFlagsAndAttributes, NULL)) ! ) == INVALID_HANDLE_VALUE) { /* * Sharing violation or locking error can indicate antivirus, backup *************** pgwin32_open(const char *fileName, int f *** 119,128 **** --- 148,166 ---- continue; } + #ifndef FRONTEND + if (wFileName) + pfree(wFileName); + #endif _dosmaperr(err); return -1; } + #ifndef FRONTEND + if (wFileName) + pfree(wFileName); + #endif + /* _open_osfhandle will, on error, set errno accordingly */ if ((fd = _open_osfhandle((long) h, fileFlags & O_APPEND)) < 0) CloseHandle(h); /* will not affect errno */