Tom Lane wrote:
> Alvaro Herrera <[email protected]> writes:
>> Does this imply that we shouldn't allow UTF8 database on Windows at all?
>
> That would be pretty unfortunate :-(
>
> I think what this suggests is that there probably needs to be some
> encoding conversion logic near the places we examine localeconv()
> output.
Attached is a patch to the current CVS.
It uses a similar way like LC_TIME stuff does.
regards,
Hiroshi Inoue
Index: pg_locale.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v
retrieving revision 1.49
diff -c -c -r1.49 pg_locale.c
*** pg_locale.c 1 Apr 2009 09:17:32 -0000 1.49
--- pg_locale.c 22 Apr 2009 21:08:33 -0000
***************
*** 386,391 ****
--- 386,449 ----
free(s->positive_sign);
}
+ #ifdef WIN32
+ #define MAX_BYTES_PER_CHARACTER 4
+ static char *dbstr_win32(bool matchenc, const char *str)
+ {
+ int encoding = GetDatabaseEncoding();
+ bool is_ascii = true;
+ size_t len, ilen, wclen, dstlen;
+ wchar_t *wbuf;
+ char *dst, *ibuf;
+
+ if (matchenc)
+ return strdup(str);
+ /* Is the str an ascii string ? */
+ for (ibuf = str; *ibuf; ibuf++)
+ {
+ if (!isascii(*ibuf))
+ {
+ is_ascii = false;
+ break;
+ }
+ }
+ /* Simply returns the strdup()ed ascii string */
+ if (is_ascii)
+ return strdup(str);
+
+ ilen = strlen(str) + 1;
+ wclen = ilen * sizeof(wchar_t);
+ wbuf = (wchar_t *) palloc(wclen);
+ len = mbstowcs(wbuf, str, ilen);
+ if (len == -1)
+ elog(ERROR,
+ "could not convert string to Wide characters:error
%lu", GetLastError());
+
+ dstlen = len * MAX_BYTES_PER_CHARACTER + 1;
+ dst = malloc(dstlen);
+
+ len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL,
NULL);
+ pfree(wbuf);
+ 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);
+ pfree(convstr);
+ }
+ }
+
+ return dst;
+ }
+
+ #define strdup(str) dbstr_win32(is_encoding_match, str)
+ #endif /* WIN32 */
/*
* Return the POSIX lconv struct (contains number/money formatting
***************
*** 398,403 ****
--- 456,466 ----
struct lconv *extlconv;
char *save_lc_monetary;
char *save_lc_numeric;
+ #ifdef WIN32
+ char *save_lc_ctype = NULL;
+ bool lc_ctype_change = false, is_encoding_match;
+ #endif /* WIN32 */
+
/* Did we do it already? */
if (CurrentLocaleConvValid)
***************
*** 413,418 ****
--- 476,492 ----
if (save_lc_numeric)
save_lc_numeric = pstrdup(save_lc_numeric);
+ #ifdef WIN32
+ save_lc_ctype = setlocale(LC_CTYPE, NULL);
+ if (save_lc_ctype && stricmp(locale_monetary, save_lc_ctype) != 0)
+ {
+ lc_ctype_change = true;
+ save_lc_ctype = pstrdup(save_lc_ctype);
+ setlocale(LC_CTYPE, locale_monetary);
+ }
+ is_encoding_match = (pg_get_encoding_from_locale(locale_monetary) ==
GetDatabaseEncoding());
+ #endif
+
setlocale(LC_MONETARY, locale_monetary);
setlocale(LC_NUMERIC, locale_numeric);
***************
*** 437,442 ****
--- 511,524 ----
CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
/* Try to restore internal settings */
+ #ifdef WIN32
+ #undef strdup
+ if (lc_ctype_change)
+ {
+ setlocale(LC_CTYPE, save_lc_ctype);
+ pfree(save_lc_ctype);
+ }
+ #endif /* WIN32 */
if (save_lc_monetary)
{
setlocale(LC_MONETARY, save_lc_monetary);
--
Sent via pgsql-general mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general