Skip to content

Commit b577aa9

Browse files
committed
Fix bug when localized to_char() day or month names were incorectly
trnasformed to lower or upper string. Pavel Stehule
1 parent a37b006 commit b577aa9

File tree

2 files changed

+206
-17
lines changed

2 files changed

+206
-17
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 129 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.119 2007/02/08 03:22:28 momjian Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.120 2007/02/08 18:19:33 momjian Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
@@ -82,6 +82,7 @@
8282
#include "utils/int8.h"
8383
#include "utils/numeric.h"
8484
#include "utils/pg_locale.h"
85+
#include "mb/pg_wchar.h"
8586

8687
#define _(x) gettext((x))
8788

@@ -113,6 +114,7 @@
113114
#define MAXFLOATWIDTH 64
114115
#define MAXDOUBLEWIDTH 128
115116

117+
116118
/* ----------
117119
* External (defined in PgSQL datetime.c (timestamp utils))
118120
* ----------
@@ -946,6 +948,20 @@ static char *localize_month(int index);
946948
static char *localize_day_full(int index);
947949
static char *localize_day(int index);
948950

951+
/*
952+
* External (defined in oracle_compat.c
953+
*/
954+
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
955+
#define USE_WIDE_UPPER_LOWER
956+
extern char *wstring_upper(char *str);
957+
extern char *wstring_lower(char *str);
958+
static char *localized_str_toupper(char *buff);
959+
static char *localized_str_tolower(char *buff);
960+
#else
961+
#define localized_str_toupper str_toupper
962+
#define localized_str_tolower str_tolower
963+
#endif
964+
949965
/* ----------
950966
* Fast sequential search, use index for data selection which
951967
* go to seq. cycle (it is very fast for unwanted strings)
@@ -1500,6 +1516,7 @@ str_toupper(char *buff)
15001516
*p_buff = pg_toupper((unsigned char) *p_buff);
15011517
++p_buff;
15021518
}
1519+
15031520
return buff;
15041521
}
15051522

@@ -1523,6 +1540,61 @@ str_tolower(char *buff)
15231540
return buff;
15241541
}
15251542

1543+
1544+
#ifdef USE_WIDE_UPPER_LOWER
1545+
/* ----------
1546+
* Convert localized string to upper string. Input string is modified in place.
1547+
* ----------
1548+
*/
1549+
static char *
1550+
localized_str_toupper(char *buff)
1551+
{
1552+
if (!buff)
1553+
return NULL;
1554+
1555+
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
1556+
return wstring_upper(buff);
1557+
else
1558+
{
1559+
char *p_buff = buff;
1560+
1561+
while (*p_buff)
1562+
{
1563+
*p_buff = pg_toupper((unsigned char) *p_buff);
1564+
++p_buff;
1565+
}
1566+
}
1567+
1568+
return buff;
1569+
}
1570+
1571+
/* ----------
1572+
* Convert localized string to upper string. Input string is modified in place.
1573+
* ----------
1574+
*/
1575+
static char *
1576+
localized_str_tolower(char *buff)
1577+
{
1578+
if (!buff)
1579+
return NULL;
1580+
1581+
if (pg_database_encoding_max_length() > 1 && !lc_ctype_is_c())
1582+
return wstring_lower(buff);
1583+
else
1584+
{
1585+
char *p_buff = buff;
1586+
1587+
while (*p_buff)
1588+
{
1589+
*p_buff = pg_tolower((unsigned char) *p_buff);
1590+
++p_buff;
1591+
}
1592+
}
1593+
1594+
return buff;
1595+
}
1596+
#endif /* USE_WIDE_UPPER_LOWER */
1597+
15261598
/* ----------
15271599
* Sequential search with to upper/lower conversion
15281600
* ----------
@@ -2182,10 +2254,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
21822254
if (!tm->tm_mon)
21832255
return -1;
21842256
if (S_TM(suf))
2257+
{
21852258
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
2259+
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
2260+
}
21862261
else
2262+
{
21872263
strcpy(workbuff, months_full[tm->tm_mon - 1]);
2188-
sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
2264+
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
2265+
}
21892266
return strlen(p_inout);
21902267

21912268
case DCH_Month:
@@ -2203,21 +2280,31 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
22032280
if (!tm->tm_mon)
22042281
return -1;
22052282
if (S_TM(suf))
2206-
sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
2283+
{
2284+
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
2285+
sprintf(inout, "%*s", 0, localized_str_tolower(workbuff));
2286+
}
22072287
else
2288+
{
22082289
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
2209-
*inout = pg_tolower((unsigned char) *inout);
2290+
*inout = pg_tolower((unsigned char) *inout);
2291+
}
22102292
return strlen(p_inout);
22112293

22122294
case DCH_MON:
22132295
INVALID_FOR_INTERVAL;
22142296
if (!tm->tm_mon)
22152297
return -1;
22162298
if (S_TM(suf))
2217-
strcpy(inout, localize_month(tm->tm_mon - 1));
2299+
{
2300+
strcpy(workbuff, localize_month(tm->tm_mon - 1));
2301+
strcpy(inout, localized_str_toupper(workbuff));
2302+
}
22182303
else
2304+
{
22192305
strcpy(inout, months[tm->tm_mon - 1]);
2220-
str_toupper(inout);
2306+
str_toupper(inout);
2307+
}
22212308
return strlen(p_inout);
22222309

22232310
case DCH_Mon:
@@ -2235,10 +2322,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
22352322
if (!tm->tm_mon)
22362323
return -1;
22372324
if (S_TM(suf))
2238-
strcpy(inout, localize_month(tm->tm_mon - 1));
2325+
{
2326+
strcpy(workbuff, localize_month(tm->tm_mon - 1));
2327+
strcpy(inout, localized_str_tolower(workbuff));
2328+
}
22392329
else
2330+
{
22402331
strcpy(inout, months[tm->tm_mon - 1]);
2241-
*inout = pg_tolower((unsigned char) *inout);
2332+
*inout = pg_tolower((unsigned char) *inout);
2333+
}
22422334
return strlen(p_inout);
22432335

22442336
case DCH_MM:
@@ -2266,36 +2358,52 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
22662358
case DCH_DAY:
22672359
INVALID_FOR_INTERVAL;
22682360
if (S_TM(suf))
2361+
{
22692362
strcpy(workbuff, localize_day_full(tm->tm_wday));
2363+
sprintf(inout, "%*s", 0, localized_str_toupper(workbuff));
2364+
}
22702365
else
2366+
{
22712367
strcpy(workbuff, days[tm->tm_wday]);
2272-
sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
2368+
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(workbuff));
2369+
}
22732370
return strlen(p_inout);
22742371

22752372
case DCH_Day:
22762373
INVALID_FOR_INTERVAL;
22772374
if (S_TM(suf))
2278-
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
2375+
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
22792376
else
22802377
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
22812378
return strlen(p_inout);
22822379

22832380
case DCH_day:
22842381
INVALID_FOR_INTERVAL;
22852382
if (S_TM(suf))
2286-
sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
2383+
{
2384+
strcpy(workbuff, localize_day_full(tm->tm_wday));
2385+
sprintf(inout, "%*s", 0, localized_str_tolower(workbuff));
2386+
}
22872387
else
2388+
{
22882389
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
2289-
*inout = pg_tolower((unsigned char) *inout);
2390+
*inout = pg_tolower((unsigned char) *inout);
2391+
}
22902392
return strlen(p_inout);
22912393

22922394
case DCH_DY:
22932395
INVALID_FOR_INTERVAL;
22942396
if (S_TM(suf))
2295-
strcpy(inout, localize_day(tm->tm_wday));
2397+
{
2398+
strcpy(workbuff, localize_day(tm->tm_wday));
2399+
strcpy(inout, localized_str_toupper(workbuff));
2400+
}
22962401
else
2402+
{
22972403
strcpy(inout, days_short[tm->tm_wday]);
2298-
str_toupper(inout);
2404+
str_toupper(inout);
2405+
}
2406+
22992407
return strlen(p_inout);
23002408

23012409
case DCH_Dy:
@@ -2309,10 +2417,15 @@ dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
23092417
case DCH_dy:
23102418
INVALID_FOR_INTERVAL;
23112419
if (S_TM(suf))
2312-
strcpy(inout, localize_day(tm->tm_wday));
2420+
{
2421+
strcpy(workbuff, localize_day(tm->tm_wday));
2422+
strcpy(inout, localized_str_tolower(workbuff));
2423+
}
23132424
else
2425+
{
23142426
strcpy(inout, days_short[tm->tm_wday]);
2315-
*inout = pg_tolower((unsigned char) *inout);
2427+
*inout = pg_tolower((unsigned char) *inout);
2428+
}
23162429
return strlen(p_inout);
23172430

23182431
case DCH_DDD:

src/backend/utils/adt/oracle_compat.c

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.68 2007/01/05 22:19:41 momjian Exp $
12+
* $PostgreSQL: pgsql/src/backend/utils/adt/oracle_compat.c,v 1.69 2007/02/08 18:19:33 momjian Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -46,6 +46,8 @@
4646
*/
4747
#if defined(HAVE_WCSTOMBS) && defined(HAVE_TOWLOWER)
4848
#define USE_WIDE_UPPER_LOWER
49+
char *wstring_lower (char *str);
50+
char *wstring_upper(char *str);
4951
#endif
5052

5153
static text *dotrim(const char *string, int stringlen,
@@ -258,6 +260,80 @@ win32_wcstotext(const wchar_t *str, int ncodes)
258260
#define wcstotext win32_wcstotext
259261
#endif /* WIN32 */
260262

263+
#ifdef USE_WIDE_UPPER_LOWER
264+
/*
265+
* string_upper and string_lower are used for correct multibyte upper/lower
266+
* transformations localized strings. Returns pointers to transformated
267+
* string.
268+
*/
269+
char *
270+
wstring_upper(char *str)
271+
{
272+
wchar_t *workspace;
273+
text *in_text;
274+
text *out_text;
275+
char *result;
276+
int nbytes = strlen(str);
277+
int i;
278+
279+
in_text = palloc(nbytes + VARHDRSZ);
280+
memcpy(VARDATA(in_text), str, nbytes);
281+
VARATT_SIZEP(in_text) = nbytes + VARHDRSZ;
282+
283+
workspace = texttowcs(in_text);
284+
285+
for (i = 0; workspace[i] != 0; i++)
286+
workspace[i] = towupper(workspace[i]);
287+
288+
out_text = wcstotext(workspace, i);
289+
290+
nbytes = VARSIZE(out_text) - VARHDRSZ;
291+
result = palloc(nbytes + 1);
292+
memcpy(result, VARDATA(out_text), nbytes);
293+
294+
result[nbytes] = '\0';
295+
296+
pfree(workspace);
297+
pfree(in_text);
298+
pfree(out_text);
299+
300+
return result;
301+
}
302+
303+
char *
304+
wstring_lower(char *str)
305+
{
306+
wchar_t *workspace;
307+
text *in_text;
308+
text *out_text;
309+
char *result;
310+
int nbytes = strlen(str);
311+
int i;
312+
313+
in_text = palloc(nbytes + VARHDRSZ);
314+
memcpy(VARDATA(in_text), str, nbytes);
315+
VARATT_SIZEP(in_text) = nbytes + VARHDRSZ;
316+
317+
workspace = texttowcs(in_text);
318+
319+
for (i = 0; workspace[i] != 0; i++)
320+
workspace[i] = towlower(workspace[i]);
321+
322+
out_text = wcstotext(workspace, i);
323+
324+
nbytes = VARSIZE(out_text) - VARHDRSZ;
325+
result = palloc(nbytes + 1);
326+
memcpy(result, VARDATA(out_text), nbytes);
327+
328+
result[nbytes] = '\0';
329+
330+
pfree(workspace);
331+
pfree(in_text);
332+
pfree(out_text);
333+
334+
return result;
335+
}
336+
#endif /* USE_WIDE_UPPER_LOWER */
261337

262338
/********************************************************************
263339
*

0 commit comments

Comments
 (0)