"Pavel Stehule" <[EMAIL PROTECTED]> writes:
> This patch correct bug, when localized day or month names was incorectly
> trnasformed to lower or upper string.
I really dislike the API you've chosen for upper_str/lower_str ---
overwriting the input on the assumption that it's long enough is a
buffer overrun bug waiting to happen, because (at least in utf8)
changing case doesn't preserve the byte length of the string.
Please make them return a freshly palloc'd string instead.
regards, tom lane
I correct it, and test it for czech latin2 and utf8 case.
Regards
Pavel Stehule
_________________________________________________________________
Chcete sdilet sve obrazky a hudbu s prateli? http://messenger.msn.cz/
*** ./adt/formatting.c.orig 2007-02-04 13:09:09.000000000 +0100
--- ./adt/formatting.c 2007-02-05 21:45:26.000000000 +0100
***************
*** 82,87 ****
--- 82,88 ----
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
+ #include "mb/pg_wchar.h"
#define _(x) gettext((x))
***************
*** 113,118 ****
--- 114,120 ----
#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
+
/* ----------
* External (defined in PgSQL datetime.c (timestamp utils))
* ----------
***************
*** 946,951 ****
--- 948,967 ----
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,1505 ****
--- 1516,1522 ----
*p_buff = pg_toupper((unsigned char) *p_buff);
++p_buff;
}
+
return buff;
}
***************
*** 1523,1528 ****
--- 1540,1600 ----
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
* ----------
***************
*** 2188,2197 ****
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
else
strcpy(workbuff, months_full[tm->tm_mon - 1]);
! sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
return strlen(p_inout);
case DCH_Month:
--- 2260,2274 ----
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) ? 0 : -9, str_toupper(workbuff));
! }
return strlen(p_inout);
case DCH_Month:
***************
*** 2209,2218 ****
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
! sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
else
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
! *inout = pg_tolower((unsigned char) *inout);
return strlen(p_inout);
case DCH_MON:
--- 2286,2300 ----
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_tolower(workbuff));
! }
else
+ {
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
! *inout = pg_tolower((unsigned char) *inout);
! }
return strlen(p_inout);
case DCH_MON:
***************
*** 2220,2229 ****
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
! strcpy(inout, localize_month(tm->tm_mon - 1));
else
strcpy(inout, months[tm->tm_mon - 1]);
! str_toupper(inout);
return strlen(p_inout);
case DCH_Mon:
--- 2302,2316 ----
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
! {
! 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);
! }
return strlen(p_inout);
case DCH_Mon:
***************
*** 2241,2250 ****
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
! strcpy(inout, localize_month(tm->tm_mon - 1));
else
strcpy(inout, months[tm->tm_mon - 1]);
! *inout = pg_tolower((unsigned char) *inout);
return strlen(p_inout);
case DCH_MM:
--- 2328,2342 ----
if (!tm->tm_mon)
return -1;
if (S_TM(suf))
! {
! 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);
! }
return strlen(p_inout);
case DCH_MM:
***************
*** 2272,2287 ****
case DCH_DAY:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
strcpy(workbuff, localize_day_full(tm->tm_wday));
else
strcpy(workbuff, days[tm->tm_wday]);
! sprintf(inout, "%*s", (S_FM(suf) || S_TM(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));
else
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
return strlen(p_inout);
--- 2364,2384 ----
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) ? 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));
else
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
return strlen(p_inout);
***************
*** 2289,2307 ****
case DCH_day:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
! sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
else
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
! *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));
else
strcpy(inout, days_short[tm->tm_wday]);
! str_toupper(inout);
return strlen(p_inout);
case DCH_Dy:
--- 2386,2415 ----
case DCH_day:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
! {
! 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);
! }
return strlen(p_inout);
case DCH_DY:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
! {
! strcpy(workbuff, localize_day(tm->tm_wday));
! strcpy(inout, localized_str_toupper(workbuff));
! }
else
+ {
strcpy(inout, days_short[tm->tm_wday]);
! str_toupper(inout);
! }
!
return strlen(p_inout);
case DCH_Dy:
***************
*** 2315,2324 ****
case DCH_dy:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
! strcpy(inout, localize_day(tm->tm_wday));
else
strcpy(inout, days_short[tm->tm_wday]);
! *inout = pg_tolower((unsigned char) *inout);
return strlen(p_inout);
case DCH_DDD:
--- 2423,2437 ----
case DCH_dy:
INVALID_FOR_INTERVAL;
if (S_TM(suf))
! {
! 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);
! }
return strlen(p_inout);
case DCH_DDD:
*** ./adt/oracle_compat.c.orig 2007-02-04 12:35:14.000000000 +0100
--- ./adt/oracle_compat.c 2007-02-05 21:03:43.000000000 +0100
***************
*** 46,51 ****
--- 46,53 ----
*/
#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,263 ****
--- 260,339 ----
#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 */
/********************************************************************
*
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?
http://www.postgresql.org/docs/faq