Fix bug when localized to_char() day or month names were incorectly
authorBruce Momjian <bruce@momjian.us>
Thu, 8 Feb 2007 18:19:33 +0000 (18:19 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 8 Feb 2007 18:19:33 +0000 (18:19 +0000)
trnasformed to lower or upper string.

Pavel Stehule

src/backend/utils/adt/formatting.c
src/backend/utils/adt/oracle_compat.c

index cbc109649951b01367c6b712d885fbf41fce93cf..91ef1ea9dcade0d4a07cea45995663819b49f254 100644 (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))
 
 #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:
index c6c4175dd6b0d026feedce4db2ab791d6ae12f14..6da6b30cca3b862a7821ddc40f8698a215c28a87 100644 (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 */
 
 /********************************************************************
  *