/* -----------------------------------------------------------------------
  * formatting.c
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.116.2.2 2007/02/08 20:33:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.116.2.3 2007/06/29 01:51:49 tgl Exp $
  *
  *
  *      Portions Copyright (c) 1999-2006, PostgreSQL Global Development Group
 #include <unistd.h>
 #include <math.h>
 #include <float.h>
+#include <limits.h>
 #include <locale.h>
 
 #include "utils/builtins.h"
  * More is in float.c
  * ----------
  */
-#define MAXFLOATWIDTH  64
-#define MAXDOUBLEWIDTH 128
+#define MAXFLOATWIDTH  60
+#define MAXDOUBLEWIDTH 500
 
 
 /* ----------
 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
+/* externs are in oracle_compat.c */
 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
 }
 
 /* ----------
- * Convert string to upper-string. Input string is modified in place.
+ * Convert string to upper case. Input string is modified in place.
  * ----------
  */
 static char *
 }
 
 /* ----------
- * Convert string to lower-string. Input string is modified in place.
+ * Convert string to lower case. Input string is modified in place.
  * ----------
  */
 static char *
 
 #ifdef USE_WIDE_UPPER_LOWER
 /* ----------
- * Convert localized string to upper string. Input string is modified in place.
+ * Convert localized string to upper case.
+ * Input string may be modified in place ... or we might make a copy.
  * ----------
  */
 static char *
 }
 
 /* ----------
- * Convert localized string to upper string. Input string is modified in place.
+ * Convert localized string to lower case.
+ * Input string may be modified in place ... or we might make a copy.
  * ----------
  */
 static char *
                        INVALID_FOR_INTERVAL;
                        if (is_to_char && tmtcTzn(tmtc))
                        {
-                               int                     siz = strlen(tmtcTzn(tmtc));
-
                                if (arg == DCH_TZ)
                                        strcpy(inout, tmtcTzn(tmtc));
                                else
                                {
-                                       char       *p = palloc(siz);
+                                       char       *p = pstrdup(tmtcTzn(tmtc));
 
-                                       strcpy(p, tmtcTzn(tmtc));
                                        strcpy(inout, str_tolower(p));
                                        pfree(p);
                                }
-                               return siz;
+                               return strlen(inout);
                        }
                        else if (!is_to_char)
                                ereport(ERROR,
 fill_str(char *str, int c, int max)
 {
        memset(str, c, max);
-       *(str + max + 1) = '\0';
+       *(str + max) = '\0';
        return str;
 }
 
 #define NUM_TOCHAR_prepare \
 do { \
        len = VARSIZE(fmt) - VARHDRSZ;                                  \
-       if (len <= 0)                                                   \
+       if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ)             \
                return DirectFunctionCall1(textin, CStringGetDatum(""));        \
-       result  = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
-       memset(result, 0,  (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
+       result  = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ);    \
        format  = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);              \
 } while (0)
 
  */
 #define NUM_TOCHAR_finish \
 do { \
-       NUM_processor(format, &Num, VARDATA(result),                    \
-               numstr, plen, sign, true);                              \
-       pfree(orgnum);                                                  \
+       NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true); \
                                                                        \
-       if (shouldFree)                                                 \
-               pfree(format);                                          \
+       if (shouldFree)                                 \
+               pfree(format);                          \
                                                                        \
-       /*
-        * for result is allocated max memory, which current format-picture\
-        * needs, now it must be re-allocate to result real size        \
+       /*                                                              \
+        * Convert null-terminated representation of result to standard text. \
+        * The result is usually much bigger than it needs to be, but there \
+        * seems little point in realloc'ing it smaller. \
         */                                                             \
-       if (!(len = strlen(VARDATA(result))))                           \
-       {                                                               \
-               pfree(result);                                          \
-               PG_RETURN_NULL();                                       \
-       }                                                               \
-                                                                       \
-       result_tmp      = result;                                       \
-       result          = (text *) palloc( len + 1 + VARHDRSZ);         \
-                                                                       \
-       strcpy( VARDATA(result), VARDATA(result_tmp));                  \
-       VARATT_SIZEP(result) = len + VARHDRSZ;                          \
-       pfree(result_tmp);                                              \
-} while(0)
+       len = strlen(VARDATA(result));  \
+       VARATT_SIZEP(result) = len + VARHDRSZ;  \
+} while (0)
 
 /* -------------------
  * NUMERIC to_number() (convert string to numeric)
 
        len = VARSIZE(fmt) - VARHDRSZ;
 
-       if (len <= 0)
+       if (len <= 0 || len >= INT_MAX/NUM_MAX_ITEM_SIZ)
                PG_RETURN_NULL();
 
        format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
                numstr = orgnum =
                        int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
                                                                                                           NumericGetDatum(x))));
-               pfree(x);
        }
        else
        {
                        val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
                                                                                                          NumericGetDatum(value),
                                                                                                          NumericGetDatum(x)));
-                       pfree(x);
-                       pfree(a);
-                       pfree(b);
                        Num.pre += Num.multi;
                }
 
                                                                                                Int32GetDatum(Num.post)));
                orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
                                                                                                         NumericGetDatum(x)));
-               pfree(x);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
                        numstr = orgnum + 1;
                }
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
-
-               if (IS_MULTI(&Num))
-                       pfree(val);
        }
 
        NUM_TOCHAR_finish;
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
                        orgnum = DatumGetCString(DirectFunctionCall1(int4out,
                                                                                                          Int32GetDatum(value)));
                }
-               len = strlen(orgnum);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
-                       --len;
+                       orgnum++;
                }
                else
                        sign = '+';
+               len = strlen(orgnum);
 
                if (Num.post)
                {
-                       int                     i;
-
                        numstr = (char *) palloc(len + Num.post + 2);
-                       strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
+                       strcpy(numstr, orgnum);
                        *(numstr + len) = '.';
-
-                       for (i = len + 1; i <= len + Num.post; i++)
-                               *(numstr + i) = '0';
+                       memset(numstr + len + 1, '0', Num.post);
                        *(numstr + len + Num.post + 1) = '\0';
-                       pfree(orgnum);
-                       orgnum = numstr;
                }
                else
-                       numstr = orgnum + (*orgnum == '-' ? 1 : 0);
+                       numstr = orgnum;
 
                if (Num.pre > len)
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
 
                orgnum = DatumGetCString(DirectFunctionCall1(int8out,
                                                                                                         Int64GetDatum(value)));
-               len = strlen(orgnum);
 
                if (*orgnum == '-')
-               {                                               /* < 0 */
+               {
                        sign = '-';
-                       --len;
+                       orgnum++;
                }
                else
                        sign = '+';
+               len = strlen(orgnum);
 
                if (Num.post)
                {
-                       int                     i;
-
                        numstr = (char *) palloc(len + Num.post + 2);
-                       strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
+                       strcpy(numstr, orgnum);
                        *(numstr + len) = '.';
-
-                       for (i = len + 1; i <= len + Num.post; i++)
-                               *(numstr + i) = '0';
+                       memset(numstr + len + 1, '0', Num.post);
                        *(numstr + len + Num.post + 1) = '\0';
-                       pfree(orgnum);
-                       orgnum = numstr;
                }
                else
-                       numstr = orgnum + (*orgnum == '-' ? 1 : 0);
+                       numstr = orgnum;
 
                if (Num.pre > len)
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }
 
        text       *fmt = PG_GETARG_TEXT_P(1);
        NUMDesc         Num;
        FormatNode *format;
-       text       *result,
-                          *result_tmp;
+       text       *result;
        bool            shouldFree;
        int                     len = 0,
                                plen = 0,
                        plen = Num.pre - len;
                else if (len > Num.pre)
                {
-                       fill_str(numstr, '#', Num.pre);
+                       numstr = (char *) palloc(Num.pre + Num.post + 2);
+                       fill_str(numstr, '#', Num.pre + Num.post + 1);
                        *(numstr + Num.pre) = '.';
-                       fill_str(numstr + 1 + Num.pre, '#', Num.post);
                }
        }