]> granicus.if.org Git - postgresql/commitdiff
Write to the Windows eventlog in UTF16, converting the message encoding
authorMagnus Hagander <magnus@hagander.net>
Sat, 17 Oct 2009 00:24:51 +0000 (00:24 +0000)
committerMagnus Hagander <magnus@hagander.net>
Sat, 17 Oct 2009 00:24:51 +0000 (00:24 +0000)
as necessary.

Itagaki Takahiro with some changes from me

src/backend/utils/error/elog.c
src/backend/utils/mb/encnames.c
src/backend/utils/mb/mbutils.c
src/include/mb/pg_wchar.h

index 06a78f2d701b91545664024aa01a1717315f2391..5f30e7837565f634975ca7e0057ca44ad7e34240 100644 (file)
@@ -42,7 +42,7 @@
  *
  *
  * 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;
 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);
+static void write_eventlog(int level, const char *line, int len);
 #endif
 
 /* We provide a small stack of ErrorData records for re-entrant cases */
@@ -1567,10 +1569,11 @@ write_syslog(int level, const char *line)
  * Write a message line to the windows event log
  */
 static void
-write_eventlog(int level, const char *line)
+write_eventlog(int level, const char *line, int len)
 {
-       int                     eventlevel = EVENTLOG_ERROR_TYPE;
-       static HANDLE evtHandle = INVALID_HANDLE_VALUE;
+       WCHAR              *utf16;
+       int                             eventlevel = EVENTLOG_ERROR_TYPE;
+       static HANDLE   evtHandle = INVALID_HANDLE_VALUE;
 
        if (evtHandle == INVALID_HANDLE_VALUE)
        {
@@ -1606,8 +1609,34 @@ write_eventlog(int level, const char *line)
                        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,
                                0,
                                0,                              /* All events are Id 0 */
@@ -1619,6 +1648,52 @@ write_eventlog(int level, const char *line)
 }
 #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
  */
@@ -2206,7 +2281,7 @@ send_message_to_server_log(ErrorData *edata)
        /* Write to eventlog, if enabled */
        if (Log_destination & LOG_DESTINATION_EVENTLOG)
        {
-               write_eventlog(edata->elevel, buf.data);
+               write_eventlog(edata->elevel, buf.data, buf.len);
        }
 #endif   /* WIN32 */
 
@@ -2230,10 +2305,10 @@ send_message_to_server_log(ErrorData *edata)
                 * because that's really a pipe to the syslogger process.
                 */
                else if (pgwin32_is_service())
-                       write_eventlog(edata->elevel, buf.data);
+                       write_eventlog(edata->elevel, buf.data, buf.len);
 #endif
                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 */
@@ -2256,12 +2331,12 @@ send_message_to_server_log(ErrorData *edata)
                {
                        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) &&
                                whereToSendOutput != DestDebug)
                        {
                                /* 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);
                }
@@ -2642,6 +2717,9 @@ void
 write_stderr(const char *fmt,...)
 {
        va_list         ap;
+#ifdef WIN32
+       char            errbuf[2048];           /* Arbitrary size? */
+#endif
 
        fmt = _(fmt);
 
@@ -2651,6 +2729,7 @@ write_stderr(const char *fmt,...)
        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
@@ -2658,16 +2737,12 @@ write_stderr(const char *fmt,...)
         */
        if (pgwin32_is_service())       /* Running as a service */
        {
-               char            errbuf[2048];           /* Arbitrary size? */
-
-               vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
-
-               write_eventlog(ERROR, errbuf);
+               write_eventlog(ERROR, errbuf, strlen(errbuf));
        }
        else
        {
                /* Not running as service, write to stderr */
-               vfprintf(stderr, fmt, ap);
+               write_console(errbuf, strlen(errbuf));
                fflush(stderr);
        }
 #endif
index def8c84bad1394e6d9603da02bb69acf1ab55c31..04df4cb5af6c91b32ce8192324c5559e58a92bd2 100644 (file)
@@ -2,7 +2,7 @@
  * Encoding names and routines for work with it. All
  * 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
 #include "postgres_fe.h"
@@ -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)
  * ----------
  */
+#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[] =
 {
-       {
-               "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
-       }
+       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)
 };
 
 /* ----------
index cd3ebb219e25550b01ea8a33f5443c250ac8522f..c6e32ef66432a1619779dac8026fbcc115b43b65 100644 (file)
@@ -4,7 +4,7 @@
  *
  * 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"
 
@@ -58,6 +58,7 @@ static FmgrInfo *ToClientConvProc = NULL;
  */
 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)
@@ -978,3 +979,66 @@ pg_client_encoding(PG_FUNCTION_ARGS)
        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 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
index e9faff001300c70b1f0c5006c7f068cac2a55fa3..353d612f758e02e7a6ab891e32efeab2ae3a5b48 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * 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
  *             This is used both by the backend and by libpq, but should not be
@@ -257,6 +257,9 @@ typedef struct pg_enc2name
 {
        char       *name;
        pg_enc          encoding;
+#ifdef WIN32
+       unsigned        codepage;       /* codepage for WIN32 */
+#endif
 } pg_enc2name;
 
 extern pg_enc2name pg_enc2name_tbl[];
@@ -402,6 +405,7 @@ extern const char *pg_get_client_encoding_name(void);
 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);
@@ -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);
 
+#ifdef WIN32
+extern WCHAR *pgwin32_toUTF16(const char *str, int len, int *utf16len);
+#endif
+
 #endif   /* PG_WCHAR_H */