44 *
55 * Portions Copyright (c) 2002-2009, PostgreSQL Global Development Group
66 *
7- * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.43 2009/01/01 17:23:49 momjian Exp $
7+ * $PostgreSQL: pgsql/src/backend/utils/adt/pg_locale.c,v 1.44 2009/01/09 13:03:55 mha Exp $
88 *
99 *-----------------------------------------------------------------------
1010 */
5151#include <time.h>
5252
5353#include "catalog/pg_control.h"
54+ #include "mb/pg_wchar.h"
5455#include "utils/memutils.h"
5556#include "utils/pg_locale.h"
5657
@@ -452,6 +453,57 @@ PGLC_localeconv(void)
452453return & CurrentLocaleConv ;
453454}
454455
456+ #ifdef WIN32
457+ /*
458+ * On win32, strftime() returns the encoding in CP_ACP, which is likely
459+ * different from SERVER_ENCODING. This is especially important in Japanese
460+ * versions of Windows which will use SJIS encoding, which we don't support
461+ * as a server encoding.
462+ *
463+ * Replace strftime() with a version that gets the string in UTF16 and then
464+ * converts it to the appropriate encoding as necessary.
465+ *
466+ * Note that this only affects the calls to strftime() in this file, which are
467+ * used to get the locale-aware strings. Other parts of the backend use
468+ * pg_strftime(), which isn't locale-aware and does not need to be replaced.
469+ */
470+ static size_t
471+ strftime_win32 (char * dst ,size_t dstlen ,const wchar_t * format ,const struct tm * tm )
472+ {
473+ size_t len ;
474+ wchar_t wbuf [MAX_L10N_DATA ];
475+ int encoding ;
476+
477+ encoding = GetDatabaseEncoding ();
478+
479+ len = wcsftime (wbuf ,sizeof (wbuf ),format ,tm );
480+ if (len == 0 )
481+ /* strftime call failed - return 0 with the contents of dst unspecified */
482+ return 0 ;
483+
484+ len = WideCharToMultiByte (CP_UTF8 ,0 ,wbuf ,len ,dst ,dstlen ,NULL ,NULL );
485+ if (len == 0 )
486+ elog (ERROR ,
487+ "could not convert string to UTF-8:error %lu" ,GetLastError ());
488+
489+ dst [len ]= '\0' ;
490+ if (encoding != PG_UTF8 )
491+ {
492+ char * convstr = pg_do_encoding_conversion (dst ,len ,PG_UTF8 ,encoding );
493+ if (dst != convstr )
494+ {
495+ StrNCpy (dst ,convstr ,dstlen );
496+ len = strlen (dst );
497+ }
498+ }
499+
500+ return len ;
501+ }
502+
503+ #define strftime (a ,b ,c ,d ) strftime_win32(a,b,L##c,d)
504+
505+ #endif /* WIN32 */
506+
455507
456508/*
457509 * Update the lc_time localization cache variables if needed.
@@ -465,13 +517,25 @@ cache_locale_time(void)
465517char buf [MAX_L10N_DATA ];
466518char * ptr ;
467519int i ;
520+ #ifdef WIN32
521+ char * save_lc_ctype ;
522+ #endif
468523
469524/* did we do this already? */
470525if (CurrentLCTimeValid )
471526return ;
472527
473528elog (DEBUG3 ,"cache_locale_time() executed; locale: \"%s\"" ,locale_time );
474529
530+ #ifdef WIN32
531+ /* set user's value of ctype locale */
532+ save_lc_ctype = setlocale (LC_CTYPE ,NULL );
533+ if (save_lc_ctype )
534+ save_lc_ctype = pstrdup (save_lc_ctype );
535+
536+ setlocale (LC_CTYPE ,locale_time );
537+ #endif
538+
475539/* set user's value of time locale */
476540save_lc_time = setlocale (LC_TIME ,NULL );
477541if (save_lc_time )
@@ -524,5 +588,14 @@ cache_locale_time(void)
524588pfree (save_lc_time );
525589}
526590
591+ #ifdef WIN32
592+ /* try to restore internal ctype settings */
593+ if (save_lc_ctype )
594+ {
595+ setlocale (LC_CTYPE ,save_lc_ctype );
596+ pfree (save_lc_ctype );
597+ }
598+ #endif
599+
527600CurrentLCTimeValid = true;
528601}