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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy