+
+#ifdef WIN32
+/*
+ * On win32, strftime() returns the encoding in CP_ACP, which is likely
+ * different from SERVER_ENCODING. This is especially important in Japanese
+ * versions of Windows which will use SJIS encoding, which we don't support
+ * as a server encoding.
+ *
+ * Replace strftime() with a version that gets the string in UTF16 and then
+ * converts it to the appropriate encoding as necessary.
+ *
+ * Note that this only affects the calls to strftime() in this file, which are
+ * used to get the locale-aware strings. Other parts of the backend use
+ * pg_strftime(), which isn't locale-aware and does not need to be replaced.
+ */
+static size_t
+strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm * tm)
+{
+ size_t len;
+ wchar_t wbuf[MAX_L10N_DATA];
+ int encoding;
+
+ encoding = GetDatabaseEncoding();
+
+ len = wcsftime(wbuf, MAX_L10N_DATA, format, tm);
+ if (len == 0)
+
+ /*
+ * strftime call failed - return 0 with the contents of dst
+ * unspecified
+ */
+ return 0;
+
+ len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL, NULL);
+ if (len == 0)
+ elog(ERROR,
+ "could not convert string to UTF-8:error %lu", GetLastError());
+
+ dst[len] = '\0';
+ if (encoding != PG_UTF8)
+ {
+ char *convstr = pg_do_encoding_conversion(dst, len, PG_UTF8, encoding);
+
+ if (dst != convstr)
+ {
+ strlcpy(dst, convstr, dstlen);
+ len = strlen(dst);
+ }
+ }
+
+ return len;
+}
+
+#define strftime(a,b,c,d) strftime_win32(a,b,L##c,d)
+#endif /* WIN32 */
+
+
+/*
+ * Update the lc_time localization cache variables if needed.
+ */
+void
+cache_locale_time(void)
+{
+ char *save_lc_time;
+ time_t timenow;
+ struct tm *timeinfo;
+ char buf[MAX_L10N_DATA];
+ char *ptr;
+ int i;
+
+#ifdef WIN32
+ char *save_lc_ctype;
+#endif
+
+ /* did we do this already? */
+ if (CurrentLCTimeValid)
+ return;
+
+ elog(DEBUG3, "cache_locale_time() executed; locale: \"%s\"", locale_time);
+
+#ifdef WIN32
+ /* set user's value of ctype locale */
+ save_lc_ctype = setlocale(LC_CTYPE, NULL);
+ if (save_lc_ctype)
+ save_lc_ctype = pstrdup(save_lc_ctype);
+
+ setlocale(LC_CTYPE, locale_time);
+#endif
+
+ /* set user's value of time locale */
+ save_lc_time = setlocale(LC_TIME, NULL);
+ if (save_lc_time)
+ save_lc_time = pstrdup(save_lc_time);
+
+ setlocale(LC_TIME, locale_time);
+
+ timenow = time(NULL);
+ timeinfo = localtime(&timenow);
+
+ /* localized days */
+ for (i = 0; i < 7; i++)
+ {
+ timeinfo->tm_wday = i;
+ strftime(buf, MAX_L10N_DATA, "%a", timeinfo);
+ ptr = MemoryContextStrdup(TopMemoryContext, buf);
+ if (localized_abbrev_days[i])
+ pfree(localized_abbrev_days[i]);
+ localized_abbrev_days[i] = ptr;
+
+ strftime(buf, MAX_L10N_DATA, "%A", timeinfo);
+ ptr = MemoryContextStrdup(TopMemoryContext, buf);
+ if (localized_full_days[i])
+ pfree(localized_full_days[i]);
+ localized_full_days[i] = ptr;
+ }
+
+ /* localized months */
+ for (i = 0; i < 12; i++)
+ {
+ timeinfo->tm_mon = i;
+ timeinfo->tm_mday = 1; /* make sure we don't have invalid date */
+ strftime(buf, MAX_L10N_DATA, "%b", timeinfo);
+ ptr = MemoryContextStrdup(TopMemoryContext, buf);
+ if (localized_abbrev_months[i])
+ pfree(localized_abbrev_months[i]);
+ localized_abbrev_months[i] = ptr;
+
+ strftime(buf, MAX_L10N_DATA, "%B", timeinfo);
+ ptr = MemoryContextStrdup(TopMemoryContext, buf);
+ if (localized_full_months[i])
+ pfree(localized_full_months[i]);
+ localized_full_months[i] = ptr;
+ }
+
+ /* try to restore internal settings */
+ if (save_lc_time)
+ {
+ setlocale(LC_TIME, save_lc_time);
+ pfree(save_lc_time);
+ }
+
+#ifdef WIN32
+ /* try to restore internal ctype settings */
+ if (save_lc_ctype)
+ {
+ setlocale(LC_CTYPE, save_lc_ctype);
+ pfree(save_lc_ctype);
+ }
+#endif
+
+ CurrentLCTimeValid = true;
+}
+
+
+#if defined(WIN32) && defined(LC_MESSAGES)
+/*
+ * Convert Windows locale name to the ISO formatted one
+ * if possible.
+ *
+ * This function returns NULL if conversion is impossible,
+ * otherwise returns the pointer to a static area which
+ * contains the iso formatted locale name.
+ */
+static
+char *
+IsoLocaleName(const char *winlocname)
+{
+#if (_MSC_VER >= 1400) /* VC8.0 or later */
+ static char iso_lc_messages[32];
+ _locale_t loct = NULL;
+
+ if (pg_strcasecmp("c", winlocname) == 0 ||
+ pg_strcasecmp("posix", winlocname) == 0)
+ {
+ strcpy(iso_lc_messages, "C");
+ return iso_lc_messages;
+ }
+
+ loct = _create_locale(LC_CTYPE, winlocname);
+ if (loct != NULL)
+ {
+ char isolang[32],
+ isocrty[32];
+ LCID lcid;
+
+ lcid = loct->locinfo->lc_handle[LC_CTYPE];
+ if (lcid == 0)
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+ _free_locale(loct);
+
+ if (!GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, isolang, sizeof(isolang)))
+ return NULL;
+ if (!GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, isocrty, sizeof(isocrty)))
+ return NULL;
+ snprintf(iso_lc_messages, sizeof(iso_lc_messages) - 1, "%s_%s", isolang, isocrty);
+ return iso_lc_messages;
+ }
+ return NULL;
+#else
+ return NULL; /* Not supported on this version of msvc/mingw */
+#endif /* _MSC_VER >= 1400 */
+}
+
+#endif /* WIN32 && LC_MESSAGES */