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:
parent
a37b006d89
commit
b577aa9ebc
@ -1,7 +1,7 @@
|
|||||||
/* -----------------------------------------------------------------------
|
/* -----------------------------------------------------------------------
|
||||||
* formatting.c
|
* 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
|
* Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
|
||||||
@ -82,6 +82,7 @@
|
|||||||
#include "utils/int8.h"
|
#include "utils/int8.h"
|
||||||
#include "utils/numeric.h"
|
#include "utils/numeric.h"
|
||||||
#include "utils/pg_locale.h"
|
#include "utils/pg_locale.h"
|
||||||
|
#include "mb/pg_wchar.h"
|
||||||
|
|
||||||
#define _(x) gettext((x))
|
#define _(x) gettext((x))
|
||||||
|
|
||||||
@ -113,6 +114,7 @@
|
|||||||
#define MAXFLOATWIDTH 64
|
#define MAXFLOATWIDTH 64
|
||||||
#define MAXDOUBLEWIDTH 128
|
#define MAXDOUBLEWIDTH 128
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* External (defined in PgSQL datetime.c (timestamp utils))
|
* 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_full(int index);
|
||||||
static char *localize_day(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
|
* Fast sequential search, use index for data selection which
|
||||||
* go to seq. cycle (it is very fast for unwanted strings)
|
* 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 = pg_toupper((unsigned char) *p_buff);
|
||||||
++p_buff;
|
++p_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1523,6 +1540,61 @@ str_tolower(char *buff)
|
|||||||
return 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
|
* 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)
|
if (!tm->tm_mon)
|
||||||
return -1;
|
return -1;
|
||||||
if (S_TM(suf))
|
if (S_TM(suf))
|
||||||
|
{
|
||||||
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
|
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
|
||||||
|
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
strcpy(workbuff, months_full[tm->tm_mon - 1]);
|
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);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_Month:
|
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)
|
if (!tm->tm_mon)
|
||||||
return -1;
|
return -1;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
|
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);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_MON:
|
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)
|
if (!tm->tm_mon)
|
||||||
return -1;
|
return -1;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
strcpy(inout, months[tm->tm_mon - 1]);
|
strcpy(inout, months[tm->tm_mon - 1]);
|
||||||
str_toupper(inout);
|
str_toupper(inout);
|
||||||
|
}
|
||||||
return strlen(p_inout);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_Mon:
|
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)
|
if (!tm->tm_mon)
|
||||||
return -1;
|
return -1;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
strcpy(inout, months[tm->tm_mon - 1]);
|
strcpy(inout, months[tm->tm_mon - 1]);
|
||||||
*inout = pg_tolower((unsigned char) *inout);
|
*inout = pg_tolower((unsigned char) *inout);
|
||||||
|
}
|
||||||
return strlen(p_inout);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_MM:
|
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:
|
case DCH_DAY:
|
||||||
INVALID_FOR_INTERVAL;
|
INVALID_FOR_INTERVAL;
|
||||||
if (S_TM(suf))
|
if (S_TM(suf))
|
||||||
|
{
|
||||||
strcpy(workbuff, localize_day_full(tm->tm_wday));
|
strcpy(workbuff, localize_day_full(tm->tm_wday));
|
||||||
|
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
strcpy(workbuff, days[tm->tm_wday]);
|
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);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_Day:
|
case DCH_Day:
|
||||||
INVALID_FOR_INTERVAL;
|
INVALID_FOR_INTERVAL;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
|
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
|
||||||
return strlen(p_inout);
|
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:
|
case DCH_day:
|
||||||
INVALID_FOR_INTERVAL;
|
INVALID_FOR_INTERVAL;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
|
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);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_DY:
|
case DCH_DY:
|
||||||
INVALID_FOR_INTERVAL;
|
INVALID_FOR_INTERVAL;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
strcpy(inout, days_short[tm->tm_wday]);
|
strcpy(inout, days_short[tm->tm_wday]);
|
||||||
str_toupper(inout);
|
str_toupper(inout);
|
||||||
|
}
|
||||||
|
|
||||||
return strlen(p_inout);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_Dy:
|
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:
|
case DCH_dy:
|
||||||
INVALID_FOR_INTERVAL;
|
INVALID_FOR_INTERVAL;
|
||||||
if (S_TM(suf))
|
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
|
else
|
||||||
|
{
|
||||||
strcpy(inout, days_short[tm->tm_wday]);
|
strcpy(inout, days_short[tm->tm_wday]);
|
||||||
*inout = pg_tolower((unsigned char) *inout);
|
*inout = pg_tolower((unsigned char) *inout);
|
||||||
|
}
|
||||||
return strlen(p_inout);
|
return strlen(p_inout);
|
||||||
|
|
||||||
case DCH_DDD:
|
case DCH_DDD:
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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)
|
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
|
||||||
#define USE_WIDE_UPPER_LOWER
|
#define USE_WIDE_UPPER_LOWER
|
||||||
|
char *wstring_lower (char *str);
|
||||||
|
char *wstring_upper(char *str);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static text *dotrim(const char *string, int stringlen,
|
static text *dotrim(const char *string, int stringlen,
|
||||||
@ -258,6 +260,80 @@ win32_wcstotext(const wchar_t *str, int ncodes)
|
|||||||
#define wcstotext win32_wcstotext
|
#define wcstotext win32_wcstotext
|
||||||
#endif /* WIN32 */
|
#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 */
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user