Fix bug when localized to_char() day or month names were incorectly

trnasformed to lower or upper string.

Pavel Stehule
This commit is contained in:
Bruce Momjian 2007-02-08 18:19:33 +00:00
parent a37b006d89
commit b577aa9ebc
2 changed files with 206 additions and 17 deletions

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------
* formatting.c
*
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.119 2007/02/08 03:22:28 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.120 2007/02/08 18:19:33 momjian Exp $
*
*
* Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
@ -82,6 +82,7 @@
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
#include "mb/pg_wchar.h"
#define _(x) gettext((x))
@ -113,6 +114,7 @@
#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
/* ----------
* External (defined in PgSQL datetime.c (timestamp utils))
* ----------
@ -946,6 +948,20 @@ static char *localize_month(int index);
static char *localize_day_full(int index);
static char *localize_day(int index);
/*
* External (defined in oracle_compat.c
*/
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
#define USE_WIDE_UPPER_LOWER
extern char *wstring_upper(char *str);
extern char *wstring_lower(char *str);
static char *localized_str_toupper(char *buff);
static char *localized_str_tolower(char *buff);
#else
#define localized_str_toupper str_toupper
#define localized_str_tolower str_tolower
#endif
/* ----------
* Fast sequential search, use index for data selection which
* go to seq. cycle (it is very fast for unwanted strings)
@ -1500,6 +1516,7 @@ str_toupper(char *buff)
*p_buff = pg_toupper((unsigned char) *p_buff);
++p_buff;
}
return buff;
}
@ -1523,6 +1540,61 @@ str_tolower(char *buff)
return buff;
}
#ifdef USE_WIDE_UPPER_LOWER
/* ----------
* Convert localized string to upper string. Input string is modified in place.
* ----------
*/
static char *
localized_str_toupper(char *buff)
{
if (!buff)
return NULL;
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
return wstring_upper(buff);
else
{
char *p_buff = buff;
while (*p_buff)
{
*p_buff = pg_toupper((unsigned char) *p_buff);
++p_buff;
}
}
return buff;
}
/* ----------
* Convert localized string to upper string. Input string is modified in place.
* ----------
*/
static char *
localized_str_tolower(char *buff)
{
if (!buff)
return NULL;
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
return wstring_lower(buff);
else
{
char *p_buff = buff;
while (*p_buff)
{
*p_buff = pg_tolower((unsigned char) *p_buff);
++p_buff;
}
}
return buff;
}
#endif /* USE_WIDE_UPPER_LOWER */
/* ----------
* Sequential search with to upper/lower conversion
* ----------
@ -2182,10 +2254,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
{
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
}
else
{
strcpy(workbuff, months_full[tm->tm_mon - 1]);
sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
}
return strlen(p_inout);
case DCH_Month:
@ -2203,10 +2280,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
{
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
sprintf(inout, "%*s", 0, localized_str_tolower(workbuff));
}
else
{
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
*inout = pg_tolower((unsigned char) *inout);
*inout = pg_tolower((unsigned char) *inout);
}
return strlen(p_inout);
case DCH_MON:
@ -2214,10 +2296,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
strcpy(inout, localize_month(tm->tm_mon - 1));
{
strcpy(workbuff, localize_month(tm->tm_mon - 1));
strcpy(inout, localized_str_toupper(workbuff));
}
else
{
strcpy(inout, months[tm->tm_mon - 1]);
str_toupper(inout);
str_toupper(inout);
}
return strlen(p_inout);
case DCH_Mon:
@ -2235,10 +2322,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
strcpy(inout, localize_month(tm->tm_mon - 1));
{
strcpy(workbuff, localize_month(tm->tm_mon - 1));
strcpy(inout, localized_str_tolower(workbuff));
}
else
{
strcpy(inout, months[tm->tm_mon - 1]);
*inout = pg_tolower((unsigned char) *inout);
*inout = pg_tolower((unsigned char) *inout);
}
return strlen(p_inout);
case DCH_MM:
@ -2266,16 +2358,21 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
case DCH_DAY:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
{
strcpy(workbuff, localize_day_full(tm->tm_wday));
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
}
else
{
strcpy(workbuff, days[tm->tm_wday]);
sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
}
return strlen(p_inout);
case DCH_Day:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
else
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
return strlen(p_inout);
@ -2283,19 +2380,30 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
case DCH_day:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
{
strcpy(workbuff, localize_day_full(tm->tm_wday));
sprintf(inout, "%*s", 0, localized_str_tolower(workbuff));
}
else
{
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
*inout = pg_tolower((unsigned char) *inout);
*inout = pg_tolower((unsigned char) *inout);
}
return strlen(p_inout);
case DCH_DY:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
strcpy(inout, localize_day(tm->tm_wday));
{
strcpy(workbuff, localize_day(tm->tm_wday));
strcpy(inout, localized_str_toupper(workbuff));
}
else
{
strcpy(inout, days_short[tm->tm_wday]);
str_toupper(inout);
str_toupper(inout);
}
return strlen(p_inout);
case DCH_Dy:
@ -2309,10 +2417,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
case DCH_dy:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
strcpy(inout, localize_day(tm->tm_wday));
{
strcpy(workbuff, localize_day(tm->tm_wday));
strcpy(inout, localized_str_tolower(workbuff));
}
else
{
strcpy(inout, days_short[tm->tm_wday]);
*inout = pg_tolower((unsigned char) *inout);
*inout = pg_tolower((unsigned char) *inout);
}
return strlen(p_inout);
case DCH_DDD:

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.68 2007/01/05 22:19:41 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.69 2007/02/08 18:19:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -46,6 +46,8 @@
*/
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
#define USE_WIDE_UPPER_LOWER
char *wstring_lower (char *str);
char *wstring_upper(char *str);
#endif
static text *dotrim(const char *string, int stringlen,
@ -258,6 +260,80 @@ win32_wcstotext(const wchar_t *str, int ncodes)
#define wcstotext win32_wcstotext
#endif /* WIN32 */
#ifdef USE_WIDE_UPPER_LOWER
/*
* string_upper and string_lower are used for correct multibyte upper/lower
* transformations localized strings. Returns pointers to transformated
* string.
*/
char *
wstring_upper(char *str)
{
wchar_t *workspace;
text *in_text;
text *out_text;
char *result;
int nbytes = strlen(str);
int i;
in_text = palloc(nbytes + VARHDRSZ);
memcpy(VARDATA(in_text), str, nbytes);
VARATT_SIZEP(in_text) = nbytes + VARHDRSZ;
workspace = texttowcs(in_text);
for (i = 0; workspace[i] != 0; i++)
workspace[i] = towupper(workspace[i]);
out_text = wcstotext(workspace, i);
nbytes = VARSIZE(out_text) - VARHDRSZ;
result = palloc(nbytes + 1);
memcpy(result, VARDATA(out_text), nbytes);
result[nbytes] = '\0';
pfree(workspace);
pfree(in_text);
pfree(out_text);
return result;
}
char *
wstring_lower(char *str)
{
wchar_t *workspace;
text *in_text;
text *out_text;
char *result;
int nbytes = strlen(str);
int i;
in_text = palloc(nbytes + VARHDRSZ);
memcpy(VARDATA(in_text), str, nbytes);
VARATT_SIZEP(in_text) = nbytes + VARHDRSZ;
workspace = texttowcs(in_text);
for (i = 0; workspace[i] != 0; i++)
workspace[i] = towlower(workspace[i]);
out_text = wcstotext(workspace, i);
nbytes = VARSIZE(out_text) - VARHDRSZ;
result = palloc(nbytes + 1);
memcpy(result, VARDATA(out_text), nbytes);
result[nbytes] = '\0';
pfree(workspace);
pfree(in_text);
pfree(out_text);
return result;
}
#endif /* USE_WIDE_UPPER_LOWER */
/********************************************************************
*