11/* -----------------------------------------------------------------------
22 * formatting.c
33 *
4- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.129 2007/02/27 23:48:08 tgl Exp $
4+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.130 2007/06/29 01:51:35 tgl Exp $
55 *
66 *
77 * Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
7474#include <unistd.h>
7575#include <math.h>
7676#include <float.h>
77+ #include <limits.h>
7778#include <locale.h>
7879
7980#include "utils/builtins.h"
112113 * More is in float.c
113114 * ----------
114115 */
115- #define MAXFLOATWIDTH 64
116- #define MAXDOUBLEWIDTH 128
116+ #define MAXFLOATWIDTH 60
117+ #define MAXDOUBLEWIDTH 500
117118
118119
119120/* ----------
@@ -958,13 +959,12 @@ static char *localize_month(int index);
958959static char * localize_day_full (int index );
959960static char * localize_day (int index );
960961
961- /*
962- * External (defined in oracle_compat.c
963- */
964962#if defined(HAVE_WCSTOMBS )&& defined(HAVE_TOWLOWER )
965963#define USE_WIDE_UPPER_LOWER
964+ /* externs are in oracle_compat.c */
966965extern char * wstring_upper (char * str );
967966extern char * wstring_lower (char * str );
967+
968968static char * localized_str_toupper (char * buff );
969969static char * localized_str_tolower (char * buff );
970970#else
@@ -1510,7 +1510,7 @@ str_numth(char *dest, char *num, int type)
15101510}
15111511
15121512/* ----------
1513- * Convert string to upper-string . Input string is modified in place.
1513+ * Convert string to upper case . Input string is modified in place.
15141514 * ----------
15151515 */
15161516static char *
@@ -1531,7 +1531,7 @@ str_toupper(char *buff)
15311531}
15321532
15331533/* ----------
1534- * Convert string to lower-string . Input string is modified in place.
1534+ * Convert string to lower case . Input string is modified in place.
15351535 * ----------
15361536 */
15371537static char *
@@ -1553,7 +1553,8 @@ str_tolower(char *buff)
15531553
15541554#ifdef USE_WIDE_UPPER_LOWER
15551555/* ----------
1556- * Convert localized string to upper string. Input string is modified in place.
1556+ * Convert localized string to upper case.
1557+ * Input string may be modified in place ... or we might make a copy.
15571558 * ----------
15581559 */
15591560static char *
@@ -1579,7 +1580,8 @@ localized_str_toupper(char *buff)
15791580}
15801581
15811582/* ----------
1582- * Convert localized string to upper string. Input string is modified in place.
1583+ * Convert localized string to lower case.
1584+ * Input string may be modified in place ... or we might make a copy.
15831585 * ----------
15841586 */
15851587static char *
@@ -2107,19 +2109,16 @@ dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
21072109INVALID_FOR_INTERVAL ;
21082110if (is_to_char && tmtcTzn (tmtc ))
21092111{
2110- int siz = strlen (tmtcTzn (tmtc ));
2111-
21122112if (arg == DCH_TZ )
21132113strcpy (inout ,tmtcTzn (tmtc ));
21142114else
21152115{
2116- char * p = palloc ( siz );
2116+ char * p = pstrdup ( tmtcTzn ( tmtc ) );
21172117
2118- strcpy (p ,tmtcTzn (tmtc ));
21192118strcpy (inout ,str_tolower (p ));
21202119pfree (p );
21212120}
2122- return siz ;
2121+ return strlen ( inout ) ;
21232122}
21242123else if (!is_to_char )
21252124ereport (ERROR ,
@@ -3624,7 +3623,7 @@ static char *
36243623fill_str (char * str ,int c ,int max )
36253624{
36263625memset (str ,c ,max );
3627- * (str + max + 1 )= '\0' ;
3626+ * (str + max )= '\0' ;
36283627return str ;
36293628}
36303629
@@ -4798,10 +4797,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
47984797#define NUM_TOCHAR_prepare \
47994798do { \
48004799len = VARSIZE(fmt) - VARHDRSZ;\
4801- if (len <= 0) \
4800+ if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
48024801return DirectFunctionCall1(textin, CStringGetDatum(""));\
4803- result= (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
4804- memset(result, 0, (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
4802+ result= (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ);\
48054803format= NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);\
48064804} while (0)
48074805
@@ -4811,30 +4809,19 @@ do { \
48114809 */
48124810#define NUM_TOCHAR_finish \
48134811do { \
4814- NUM_processor(format, &Num, VARDATA(result),\
4815- numstr, plen, sign, true);\
4816- pfree(orgnum);\
4812+ NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true);\
48174813\
4818- if (shouldFree) \
4819- pfree(format); \
4814+ if (shouldFree)\
4815+ pfree(format);\
48204816\
4821- /*
4822- * for result is allocated max memory, which current format-picture\
4823- * needs, now it must be re-allocate to result real size\
4817+ /*\
4818+ * Convert null-terminated representation of result to standard text. \
4819+ * The result is usually much bigger than it needs to be, but there \
4820+ * seems little point in realloc'ing it smaller. \
48244821 */ \
4825- if (!(len = strlen (VARDATA (result ))))\
4826- {\
4827- pfree (result );\
4828- PG_RETURN_NULL ();\
4829- }\
4830- \
4831- result_tmp = result ;\
4832- result = (text * )palloc (len + VARHDRSZ );\
4833- \
4834- memcpy (VARDATA (result ),VARDATA (result_tmp ),len );\
4835- SET_VARSIZE (result ,len + VARHDRSZ );\
4836- pfree (result_tmp );\
4837- }while (0 )
4822+ len = strlen (VARDATA (result ));\
4823+ SET_VARSIZE (result ,len + VARHDRSZ ); \
4824+ }while (0 )
48384825
48394826/* -------------------
48404827 * NUMERIC to_number() (convert string to numeric)
@@ -4856,7 +4843,7 @@ numeric_to_number(PG_FUNCTION_ARGS)
48564843
48574844len = VARSIZE (fmt )- VARHDRSZ ;
48584845
4859- if (len <=0 )
4846+ if (len <=0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ )
48604847PG_RETURN_NULL ();
48614848
48624849format = NUM_cache (len ,& Num ,VARDATA (fmt ),& shouldFree );
@@ -4891,8 +4878,7 @@ numeric_to_char(PG_FUNCTION_ARGS)
48914878text * fmt = PG_GETARG_TEXT_P (1 );
48924879NUMDesc Num ;
48934880FormatNode * format ;
4894- text * result ,
4895- * result_tmp ;
4881+ text * result ;
48964882bool shouldFree ;
48974883int len = 0 ,
48984884plen = 0 ,
@@ -4915,7 +4901,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
49154901numstr = orgnum =
49164902int_to_roman (DatumGetInt32 (DirectFunctionCall1 (numeric_int4 ,
49174903NumericGetDatum (x ))));
4918- pfree (x );
49194904}
49204905else
49214906{
@@ -4934,9 +4919,6 @@ numeric_to_char(PG_FUNCTION_ARGS)
49344919val = DatumGetNumeric (DirectFunctionCall2 (numeric_mul ,
49354920NumericGetDatum (value ),
49364921NumericGetDatum (x )));
4937- pfree (x );
4938- pfree (a );
4939- pfree (b );
49404922Num .pre += Num .multi ;
49414923}
49424924
@@ -4945,10 +4927,9 @@ numeric_to_char(PG_FUNCTION_ARGS)
49454927Int32GetDatum (Num .post )));
49464928orgnum = DatumGetCString (DirectFunctionCall1 (numeric_out ,
49474929NumericGetDatum (x )));
4948- pfree (x );
49494930
49504931if (* orgnum == '-' )
4951- {/* < 0 */
4932+ {
49524933sign = '-' ;
49534934numstr = orgnum + 1 ;
49544935}
@@ -4966,13 +4947,10 @@ numeric_to_char(PG_FUNCTION_ARGS)
49664947plen = Num .pre - len ;
49674948else if (len > Num .pre )
49684949{
4969- fill_str (numstr ,'#' ,Num .pre );
4950+ numstr = (char * )palloc (Num .pre + Num .post + 2 );
4951+ fill_str (numstr ,'#' ,Num .pre + Num .post + 1 );
49704952* (numstr + Num .pre )= '.' ;
4971- fill_str (numstr + 1 + Num .pre ,'#' ,Num .post );
49724953}
4973-
4974- if (IS_MULTI (& Num ))
4975- pfree (val );
49764954}
49774955
49784956NUM_TOCHAR_finish ;
@@ -4990,8 +4968,7 @@ int4_to_char(PG_FUNCTION_ARGS)
49904968text * fmt = PG_GETARG_TEXT_P (1 );
49914969NUMDesc Num ;
49924970FormatNode * format ;
4993- text * result ,
4994- * result_tmp ;
4971+ text * result ;
49954972bool shouldFree ;
49964973int len = 0 ,
49974974plen = 0 ,
@@ -5019,40 +4996,34 @@ int4_to_char(PG_FUNCTION_ARGS)
50194996orgnum = DatumGetCString (DirectFunctionCall1 (int4out ,
50204997Int32GetDatum (value )));
50214998}
5022- len = strlen (orgnum );
50234999
50245000if (* orgnum == '-' )
5025- {/* < 0 */
5001+ {
50265002sign = '-' ;
5027- -- len ;
5003+ orgnum ++ ;
50285004}
50295005else
50305006sign = '+' ;
5007+ len = strlen (orgnum );
50315008
50325009if (Num .post )
50335010{
5034- int i ;
5035-
50365011numstr = (char * )palloc (len + Num .post + 2 );
5037- strcpy (numstr ,orgnum + ( * orgnum == '-' ? 1 : 0 ) );
5012+ strcpy (numstr ,orgnum );
50385013* (numstr + len )= '.' ;
5039-
5040- for (i = len + 1 ;i <=len + Num .post ;i ++ )
5041- * (numstr + i )= '0' ;
5014+ memset (numstr + len + 1 ,'0' ,Num .post );
50425015* (numstr + len + Num .post + 1 )= '\0' ;
5043- pfree (orgnum );
5044- orgnum = numstr ;
50455016}
50465017else
5047- numstr = orgnum + ( * orgnum == '-' ? 1 : 0 ) ;
5018+ numstr = orgnum ;
50485019
50495020if (Num .pre > len )
50505021plen = Num .pre - len ;
50515022else if (len > Num .pre )
50525023{
5053- fill_str (numstr ,'#' ,Num .pre );
5024+ numstr = (char * )palloc (Num .pre + Num .post + 2 );
5025+ fill_str (numstr ,'#' ,Num .pre + Num .post + 1 );
50545026* (numstr + Num .pre )= '.' ;
5055- fill_str (numstr + 1 + Num .pre ,'#' ,Num .post );
50565027}
50575028}
50585029
@@ -5071,8 +5042,7 @@ int8_to_char(PG_FUNCTION_ARGS)
50715042text * fmt = PG_GETARG_TEXT_P (1 );
50725043NUMDesc Num ;
50735044FormatNode * format ;
5074- text * result ,
5075- * result_tmp ;
5045+ text * result ;
50765046bool shouldFree ;
50775047int len = 0 ,
50785048plen = 0 ,
@@ -5106,40 +5076,34 @@ int8_to_char(PG_FUNCTION_ARGS)
51065076
51075077orgnum = DatumGetCString (DirectFunctionCall1 (int8out ,
51085078Int64GetDatum (value )));
5109- len = strlen (orgnum );
51105079
51115080if (* orgnum == '-' )
5112- {/* < 0 */
5081+ {
51135082sign = '-' ;
5114- -- len ;
5083+ orgnum ++ ;
51155084}
51165085else
51175086sign = '+' ;
5087+ len = strlen (orgnum );
51185088
51195089if (Num .post )
51205090{
5121- int i ;
5122-
51235091numstr = (char * )palloc (len + Num .post + 2 );
5124- strcpy (numstr ,orgnum + ( * orgnum == '-' ? 1 : 0 ) );
5092+ strcpy (numstr ,orgnum );
51255093* (numstr + len )= '.' ;
5126-
5127- for (i = len + 1 ;i <=len + Num .post ;i ++ )
5128- * (numstr + i )= '0' ;
5094+ memset (numstr + len + 1 ,'0' ,Num .post );
51295095* (numstr + len + Num .post + 1 )= '\0' ;
5130- pfree (orgnum );
5131- orgnum = numstr ;
51325096}
51335097else
5134- numstr = orgnum + ( * orgnum == '-' ? 1 : 0 ) ;
5098+ numstr = orgnum ;
51355099
51365100if (Num .pre > len )
51375101plen = Num .pre - len ;
51385102else if (len > Num .pre )
51395103{
5140- fill_str (numstr ,'#' ,Num .pre );
5104+ numstr = (char * )palloc (Num .pre + Num .post + 2 );
5105+ fill_str (numstr ,'#' ,Num .pre + Num .post + 1 );
51415106* (numstr + Num .pre )= '.' ;
5142- fill_str (numstr + 1 + Num .pre ,'#' ,Num .post );
51435107}
51445108}
51455109
@@ -5158,8 +5122,7 @@ float4_to_char(PG_FUNCTION_ARGS)
51585122text * fmt = PG_GETARG_TEXT_P (1 );
51595123NUMDesc Num ;
51605124FormatNode * format ;
5161- text * result ,
5162- * result_tmp ;
5125+ text * result ;
51635126bool shouldFree ;
51645127int len = 0 ,
51655128plen = 0 ,
@@ -5214,9 +5177,9 @@ float4_to_char(PG_FUNCTION_ARGS)
52145177plen = Num .pre - len ;
52155178else if (len > Num .pre )
52165179{
5217- fill_str (numstr ,'#' ,Num .pre );
5180+ numstr = (char * )palloc (Num .pre + Num .post + 2 );
5181+ fill_str (numstr ,'#' ,Num .pre + Num .post + 1 );
52185182* (numstr + Num .pre )= '.' ;
5219- fill_str (numstr + 1 + Num .pre ,'#' ,Num .post );
52205183}
52215184}
52225185
@@ -5235,8 +5198,7 @@ float8_to_char(PG_FUNCTION_ARGS)
52355198text * fmt = PG_GETARG_TEXT_P (1 );
52365199NUMDesc Num ;
52375200FormatNode * format ;
5238- text * result ,
5239- * result_tmp ;
5201+ text * result ;
52405202bool shouldFree ;
52415203int len = 0 ,
52425204plen = 0 ,
@@ -5289,9 +5251,9 @@ float8_to_char(PG_FUNCTION_ARGS)
52895251plen = Num .pre - len ;
52905252else if (len > Num .pre )
52915253{
5292- fill_str (numstr ,'#' ,Num .pre );
5254+ numstr = (char * )palloc (Num .pre + Num .post + 2 );
5255+ fill_str (numstr ,'#' ,Num .pre + Num .post + 1 );
52935256* (numstr + Num .pre )= '.' ;
5294- fill_str (numstr + 1 + Num .pre ,'#' ,Num .post );
52955257}
52965258}
52975259