]> granicus.if.org Git - postgresql/commitdiff
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 */
 
 /********************************************************************
  *