Commit 74877137 authored by Magnus Hagander's avatar Magnus Hagander

Write to the Windows eventlog in UTF16, converting the message encoding

as necessary.

Itagaki Takahiro with some changes from me
parent 76c09dbe
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.217 2009/07/03 19:14:25 petere Exp $ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.218 2009/10/17 00:24:50 mha Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -111,8 +111,10 @@ static int syslog_facility = LOG_LOCAL0; ...@@ -111,8 +111,10 @@ static int syslog_facility = LOG_LOCAL0;
static void write_syslog(int level, const char *line); static void write_syslog(int level, const char *line);
#endif #endif
static void write_console(const char *line, int len);
#ifdef WIN32 #ifdef WIN32
static void write_eventlog(int level, const char *line); static void write_eventlog(int level, const char *line, int len);
#endif #endif
/* We provide a small stack of ErrorData records for re-entrant cases */ /* We provide a small stack of ErrorData records for re-entrant cases */
...@@ -1567,10 +1569,11 @@ write_syslog(int level, const char *line) ...@@ -1567,10 +1569,11 @@ write_syslog(int level, const char *line)
* Write a message line to the windows event log * Write a message line to the windows event log
*/ */
static void static void
write_eventlog(int level, const char *line) write_eventlog(int level, const char *line, int len)
{ {
int eventlevel = EVENTLOG_ERROR_TYPE; WCHAR *utf16;
static HANDLE evtHandle = INVALID_HANDLE_VALUE; int eventlevel = EVENTLOG_ERROR_TYPE;
static HANDLE evtHandle = INVALID_HANDLE_VALUE;
if (evtHandle == INVALID_HANDLE_VALUE) if (evtHandle == INVALID_HANDLE_VALUE)
{ {
...@@ -1606,8 +1609,34 @@ write_eventlog(int level, const char *line) ...@@ -1606,8 +1609,34 @@ write_eventlog(int level, const char *line)
break; break;
} }
/*
ReportEvent(evtHandle, * Convert message to UTF16 text and write it with ReportEventW,
* but fall-back into ReportEventA if conversion failed.
*
* Also verify that we are not on our way into error recursion trouble
* due to error messages thrown deep inside pgwin32_toUTF16().
*/
if (GetDatabaseEncoding() != GetPlatformEncoding() &&
!in_error_recursion_trouble())
{
utf16 = pgwin32_toUTF16(line, len, NULL);
if (utf16)
{
ReportEventW(evtHandle,
eventlevel,
0,
0, /* All events are Id 0 */
NULL,
1,
0,
(LPCWSTR *) &utf16,
NULL);
pfree(utf16);
return;
}
}
ReportEventA(evtHandle,
eventlevel, eventlevel,
0, 0,
0, /* All events are Id 0 */ 0, /* All events are Id 0 */
...@@ -1619,6 +1648,52 @@ write_eventlog(int level, const char *line) ...@@ -1619,6 +1648,52 @@ write_eventlog(int level, const char *line)
} }
#endif /* WIN32 */ #endif /* WIN32 */
static void
write_console(const char *line, int len)
{
#ifdef WIN32
/*
* WriteConsoleW() will fail of stdout is redirected, so just fall through
* to writing unconverted to the logfile in this case.
*/
if (GetDatabaseEncoding() != GetPlatformEncoding() &&
!in_error_recursion_trouble() &&
!redirection_done)
{
WCHAR *utf16;
int utf16len;
utf16 = pgwin32_toUTF16(line, len, &utf16len);
if (utf16 != NULL)
{
HANDLE stdHandle;
DWORD written;
stdHandle = GetStdHandle(STD_ERROR_HANDLE);
if (WriteConsoleW(stdHandle, utf16, utf16len, &written, NULL))
{
pfree(utf16);
return;
}
/*
* In case WriteConsoleW() failed, fall back to writing the message
* unconverted.
*/
pfree(utf16);
}
}
#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 * setup formatted_log_time, for consistent times between CSV and regular logs
*/ */
...@@ -2206,7 +2281,7 @@ send_message_to_server_log(ErrorData *edata) ...@@ -2206,7 +2281,7 @@ send_message_to_server_log(ErrorData *edata)
/* Write to eventlog, if enabled */ /* Write to eventlog, if enabled */
if (Log_destination & LOG_DESTINATION_EVENTLOG) if (Log_destination & LOG_DESTINATION_EVENTLOG)
{ {
write_eventlog(edata->elevel, buf.data); write_eventlog(edata->elevel, buf.data, buf.len);
} }
#endif /* WIN32 */ #endif /* WIN32 */
...@@ -2230,10 +2305,10 @@ send_message_to_server_log(ErrorData *edata) ...@@ -2230,10 +2305,10 @@ send_message_to_server_log(ErrorData *edata)
* because that's really a pipe to the syslogger process. * because that's really a pipe to the syslogger process.
*/ */
else if (pgwin32_is_service()) else if (pgwin32_is_service())
write_eventlog(edata->elevel, buf.data); write_eventlog(edata->elevel, buf.data, buf.len);
#endif #endif
else else
write(fileno(stderr), buf.data, buf.len); write_console(buf.data, buf.len);
} }
/* If in the syslogger process, try to write messages direct to file */ /* If in the syslogger process, try to write messages direct to file */
...@@ -2256,12 +2331,12 @@ send_message_to_server_log(ErrorData *edata) ...@@ -2256,12 +2331,12 @@ send_message_to_server_log(ErrorData *edata)
{ {
const char *msg = _("Not safe to send CSV data\n"); const char *msg = _("Not safe to send CSV data\n");
write(fileno(stderr), msg, strlen(msg)); write_console(msg, strlen(msg));
if (!(Log_destination & LOG_DESTINATION_STDERR) && if (!(Log_destination & LOG_DESTINATION_STDERR) &&
whereToSendOutput != DestDebug) whereToSendOutput != DestDebug)
{ {
/* write message to stderr unless we just sent it above */ /* write message to stderr unless we just sent it above */
write(fileno(stderr), buf.data, buf.len); write_console(buf.data, buf.len);
} }
pfree(buf.data); pfree(buf.data);
} }
...@@ -2642,6 +2717,9 @@ void ...@@ -2642,6 +2717,9 @@ void
write_stderr(const char *fmt,...) write_stderr(const char *fmt,...)
{ {
va_list ap; va_list ap;
#ifdef WIN32
char errbuf[2048]; /* Arbitrary size? */
#endif
fmt = _(fmt); fmt = _(fmt);
...@@ -2651,6 +2729,7 @@ write_stderr(const char *fmt,...) ...@@ -2651,6 +2729,7 @@ write_stderr(const char *fmt,...)
vfprintf(stderr, fmt, ap); vfprintf(stderr, fmt, ap);
fflush(stderr); fflush(stderr);
#else #else
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
/* /*
* On Win32, we print to stderr if running on a console, or write to * On Win32, we print to stderr if running on a console, or write to
...@@ -2658,16 +2737,12 @@ write_stderr(const char *fmt,...) ...@@ -2658,16 +2737,12 @@ write_stderr(const char *fmt,...)
*/ */
if (pgwin32_is_service()) /* Running as a service */ if (pgwin32_is_service()) /* Running as a service */
{ {
char errbuf[2048]; /* Arbitrary size? */ write_eventlog(ERROR, errbuf, strlen(errbuf));
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
write_eventlog(ERROR, errbuf);
} }
else else
{ {
/* Not running as service, write to stderr */ /* Not running as service, write to stderr */
vfprintf(stderr, fmt, ap); write_console(errbuf, strlen(errbuf));
fflush(stderr); fflush(stderr);
} }
#endif #endif
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Encoding names and routines for work with it. All * Encoding names and routines for work with it. All
* in this file is shared bedween FE and BE. * in this file is shared bedween FE and BE.
* *
* $PostgreSQL: pgsql/src/backend/utils/mb/encnames.c,v 1.39 2009/04/24 08:43:50 mha Exp $ * $PostgreSQL: pgsql/src/backend/utils/mb/encnames.c,v 1.40 2009/10/17 00:24:51 mha Exp $
*/ */
#ifdef FRONTEND #ifdef FRONTEND
#include "postgres_fe.h" #include "postgres_fe.h"
...@@ -300,134 +300,55 @@ sizeof(pg_encname_tbl) / sizeof(pg_encname_tbl[0]) - 1; ...@@ -300,134 +300,55 @@ sizeof(pg_encname_tbl) / sizeof(pg_encname_tbl[0]) - 1;
* XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h) * XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h)
* ---------- * ----------
*/ */
#ifndef WIN32
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name }
#else
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name, codepage }
#endif
pg_enc2name pg_enc2name_tbl[] = pg_enc2name pg_enc2name_tbl[] =
{ {
{ DEF_ENC2NAME(SQL_ASCII, 0),
"SQL_ASCII", PG_SQL_ASCII DEF_ENC2NAME(EUC_JP, 20932),
}, DEF_ENC2NAME(EUC_CN, 20936),
{ DEF_ENC2NAME(EUC_KR, 51949),
"EUC_JP", PG_EUC_JP DEF_ENC2NAME(EUC_TW, 0),
}, DEF_ENC2NAME(EUC_JIS_2004, 20932),
{ DEF_ENC2NAME(UTF8, 65001),
"EUC_CN", PG_EUC_CN DEF_ENC2NAME(MULE_INTERNAL, 0),
}, DEF_ENC2NAME(LATIN1, 28591),
{ DEF_ENC2NAME(LATIN2, 28592),
"EUC_KR", PG_EUC_KR DEF_ENC2NAME(LATIN3, 28593),
}, DEF_ENC2NAME(LATIN4, 28594),
{ DEF_ENC2NAME(LATIN5, 28599),
"EUC_TW", PG_EUC_TW DEF_ENC2NAME(LATIN6, 0),
}, DEF_ENC2NAME(LATIN7, 0),
{ DEF_ENC2NAME(LATIN8, 0),
"EUC_JIS_2004", PG_EUC_JIS_2004 DEF_ENC2NAME(LATIN9, 28605),
}, DEF_ENC2NAME(LATIN10, 0),
{ DEF_ENC2NAME(WIN1256, 1256),
"UTF8", PG_UTF8 DEF_ENC2NAME(WIN1258, 1258),
}, DEF_ENC2NAME(WIN866, 866),
{ DEF_ENC2NAME(WIN874, 874),
"MULE_INTERNAL", PG_MULE_INTERNAL DEF_ENC2NAME(KOI8R, 20866),
}, DEF_ENC2NAME(WIN1251, 1251),
{ DEF_ENC2NAME(WIN1252, 1252),
"LATIN1", PG_LATIN1 DEF_ENC2NAME(ISO_8859_5, 28595),
}, DEF_ENC2NAME(ISO_8859_6, 28596),
{ DEF_ENC2NAME(ISO_8859_7, 28597),
"LATIN2", PG_LATIN2 DEF_ENC2NAME(ISO_8859_8, 28598),
}, DEF_ENC2NAME(WIN1250, 1250),
{ DEF_ENC2NAME(WIN1253, 1253),
"LATIN3", PG_LATIN3 DEF_ENC2NAME(WIN1254, 1254),
}, DEF_ENC2NAME(WIN1255, 1255),
{ DEF_ENC2NAME(WIN1257, 1257),
"LATIN4", PG_LATIN4 DEF_ENC2NAME(KOI8U, 21866),
}, DEF_ENC2NAME(SJIS, 932),
{ DEF_ENC2NAME(BIG5, 950),
"LATIN5", PG_LATIN5 DEF_ENC2NAME(GBK, 936),
}, DEF_ENC2NAME(UHC, 0),
{ DEF_ENC2NAME(GB18030, 54936),
"LATIN6", PG_LATIN6 DEF_ENC2NAME(JOHAB, 0),
}, DEF_ENC2NAME(SHIFT_JIS_2004, 932)
{
"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
}
}; };
/* ---------- /* ----------
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Tatsuo Ishii * Tatsuo Ishii
* *
* $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.89 2009/07/07 19:28:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.90 2009/10/17 00:24:51 mha Exp $
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -58,6 +58,7 @@ static FmgrInfo *ToClientConvProc = NULL; ...@@ -58,6 +58,7 @@ static FmgrInfo *ToClientConvProc = NULL;
*/ */
static pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII]; 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];
static pg_enc2name *PlatformEncoding = NULL;
/* /*
* During backend startup we can't set client encoding because we (a) * During backend startup we can't set client encoding because we (a)
...@@ -978,3 +979,66 @@ pg_client_encoding(PG_FUNCTION_ARGS) ...@@ -978,3 +979,66 @@ pg_client_encoding(PG_FUNCTION_ARGS)
Assert(ClientEncoding); Assert(ClientEncoding);
return DirectFunctionCall1(namein, CStringGetDatum(ClientEncoding->name)); 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 not.
*/
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 = len;
return utf16;
}
#endif
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.91 2009/06/11 14:49:11 momjian Exp $ * $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.92 2009/10/17 00:24:51 mha Exp $
* *
* NOTES * NOTES
* This is used both by the backend and by libpq, but should not be * This is used both by the backend and by libpq, but should not be
...@@ -257,6 +257,9 @@ typedef struct pg_enc2name ...@@ -257,6 +257,9 @@ typedef struct pg_enc2name
{ {
char *name; char *name;
pg_enc encoding; pg_enc encoding;
#ifdef WIN32
unsigned codepage; /* codepage for WIN32 */
#endif
} pg_enc2name; } pg_enc2name;
extern pg_enc2name pg_enc2name_tbl[]; extern pg_enc2name pg_enc2name_tbl[];
...@@ -402,6 +405,7 @@ extern const char *pg_get_client_encoding_name(void); ...@@ -402,6 +405,7 @@ extern const char *pg_get_client_encoding_name(void);
extern void SetDatabaseEncoding(int encoding); extern void SetDatabaseEncoding(int encoding);
extern int GetDatabaseEncoding(void); extern int GetDatabaseEncoding(void);
extern const char *GetDatabaseEncodingName(void); extern const char *GetDatabaseEncodingName(void);
extern int GetPlatformEncoding(void);
extern void pg_bind_textdomain_codeset(const char *domainname); extern void pg_bind_textdomain_codeset(const char *domainname);
extern int pg_valid_client_encoding(const char *name); extern int pg_valid_client_encoding(const char *name);
...@@ -458,4 +462,8 @@ extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p, ...@@ -458,4 +462,8 @@ extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p,
extern bool pg_utf8_islegal(const unsigned char *source, int length); 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 */ #endif /* PG_WCHAR_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment