From 4a3a1e2cf15bdb4c0cad08043bec3111cd700113 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 16 Mar 2000 01:35:41 +0000 Subject: [PATCH] Hi, small changes in formatting.c code (better memory usage ...etc.) and better to_char's cache (will fastly for more to_char()s in one query). (It is probably end of to_char() development in 7.0 cycle.) Karel --- src/backend/utils/adt/formatting.c | 577 +++++++++++++++++++---------- 1 file changed, 379 insertions(+), 198 deletions(-) diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index c324014669..2bd3f016a7 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.5 2000/03/08 01:34:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.6 2000/03/16 01:35:41 momjian Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL, Inc @@ -14,11 +14,9 @@ * * * Cache & Memory: - * Routines use (itself) internal cache for format pictures. If - * new format arg is same as a last format string, routines do not - * call the format-parser. + * Routines use (itself) internal cache for format pictures. * - * The cache uses a static buffer and is persistent across transactions. + * The cache uses a static buffers and is persistent across transactions. * If format-picture is bigger than cache buffer, parser is called always. * * NOTE for Number version: @@ -90,18 +88,11 @@ * Maximal length of one node * ---------- */ -#define DCH_MAX_ITEM_SIZ 9 /* some month name ? */ -#define NUM_MAX_ITEM_SIZ 16 /* roman number */ +#define DCH_MAX_ITEM_SIZ 9 /* max julian day */ +#define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */ /* ---------- - * Format picture cache limits - * ---------- - */ -#define NUM_CACHE_SIZE 64 -#define DCH_CACHE_SIZE 128 - -/* ---------- - * More in float.c + * More is in float.c * ---------- */ #define MAXFLOATWIDTH 64 @@ -282,6 +273,42 @@ typedef struct { #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN) #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI) +/* ---------- + * Format picture cache + * (cache size: + * Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS + * Date-time part = DCH_CACHE_SIZE * DCH_CACHE_FIELDS + * ) + * ---------- + */ +#define NUM_CACHE_SIZE 64 +#define NUM_CACHE_FIELDS 16 +#define DCH_CACHE_SIZE 128 +#define DCH_CACHE_FIELDS 16 + +typedef struct { + FormatNode format [ DCH_CACHE_SIZE +1]; + char str [ DCH_CACHE_SIZE +1]; + int age; +} DCHCacheEntry; + +typedef struct { + FormatNode format [ NUM_CACHE_SIZE +1]; + char str [ NUM_CACHE_SIZE +1]; + int age; + NUMDesc Num; +} NUMCacheEntry; + +static DCHCacheEntry DCHCache [ DCH_CACHE_FIELDS +1]; /* global cache for date/time part */ +static int n_DCHCache = 0; /* number of entries */ +static int DCHCounter = 0; + +static NUMCacheEntry NUMCache [ NUM_CACHE_FIELDS +1]; /* global cache for number part */ +static int n_NUMCache = 0; /* number of entries */ +static int NUMCounter = 0; + +#define MAX_INT32 (2147483640) + /* ---------- * Private global-modul definitions * ---------- @@ -625,8 +652,7 @@ static int dch_global(int arg, char *inout, int suf, int flag, FormatNode *node) static int dch_time(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_date(int arg, char *inout, int suf, int flag, FormatNode *node); static char *fill_str(char *str, int c, int max); -static FormatNode *NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, - NUMDesc *CacheNum, NUMDesc *Num, char *pars_str, int *flag); +static FormatNode *NUM_cache( int len, NUMDesc *Num, char *pars_str, int *flag); static char *int_to_roman(int number); static void NUM_prepare_locale(NUMProc *Np); static char *get_last_relevant_decnum(char *num); @@ -634,6 +660,10 @@ static void NUM_numpart_from_char(NUMProc *Np, int id, int plen); static void NUM_numpart_to_char(NUMProc *Np, int id); static char *NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int plen, int sign, int type); +static DCHCacheEntry *DCH_cache_search( char *str ); +static DCHCacheEntry *DCH_cache_getnew( char *str ); +static NUMCacheEntry *NUM_cache_search( char *str ); +static NUMCacheEntry *NUM_cache_getnew( char *str ); /* ---------- @@ -1259,7 +1289,7 @@ dump_index(KeyWord *k, int *index) /* ---------- - * Global format opton for DCH version + * Global format option for DCH version * ---------- */ static int @@ -1384,7 +1414,7 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) #define CHECK_SEQ_SEARCH(_l, _s) { \ if (_l <= 0) { \ - elog(ERROR, "to_datatime(): bad value for %s", _s); \ + elog(ERROR, "to_timestamp(): bad value for %s", _s); \ } \ } @@ -1778,6 +1808,84 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return -1; } +static DCHCacheEntry * +DCH_cache_getnew( char *str ) +{ + DCHCacheEntry *ent = NULL; + + /* counter overload check - paranoa? */ + if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32) { + DCHCounter = 0; + + for(ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) + ent->age = (++DCHCounter); + } + + /* ---------- + * Cache is full - needs remove any older entry + * ---------- + */ + if (n_DCHCache > DCH_CACHE_FIELDS) { + + DCHCacheEntry *old = DCHCache+0; +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Cache is full (%d)", n_DCHCache); +#endif + for(ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) { + if (ent->age < old->age) + old = ent; + } +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age); +#endif + strcpy(old->str, str); /* check str size before this func. */ + /* old->format fill parser */ + old->age = (++DCHCounter); + return old; + + } else { +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache); +#endif + ent = DCHCache + n_DCHCache; + strcpy(ent->str, str); /* check str size before this func. */ + /* ent->format fill parser */ + ent->age = (++DCHCounter); + ++n_DCHCache; + return ent; + } + + return (DCHCacheEntry *) NULL; /* never */ +} + +static DCHCacheEntry * +DCH_cache_search( char *str ) +{ + int i = 0; + DCHCacheEntry *ent; + + /* counter overload check - paranoa? */ + if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32) { + DCHCounter = 0; + + for(ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) + ent->age = (++DCHCounter); + } + + for(ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) { + if (i == n_DCHCache) + break; + if (strcmp(ent->str, str) == 0) { + ent->age = (++DCHCounter); + return ent; + } + i++; + } + + return (DCHCacheEntry *) NULL; +} + + /**************************************************************************** * Public routines ***************************************************************************/ @@ -1789,23 +1897,19 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) text * timestamp_to_char(Timestamp *dt, text *fmt) { - static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; - static char CacheStr[ DCH_CACHE_SIZE +1]; - - text *result; + text *result, *result_tmp; FormatNode *format; - int flag=0; char *str; double fsec; char *tzn; - int len=0, tz, x=0; + int len=0, tz, flag = 0, x=0; if ((!PointerIsValid(dt)) || (!PointerIsValid(fmt))) return NULL; len = VARSIZE(fmt) - VARHDRSZ; - if ((!len) || (TIMESTAMP_NOT_FINITE(*dt))) + if ((!len) || (TIMESTAMP_NOT_FINITE(*dt))) return textin(""); tm->tm_sec =0; tm->tm_year =0; @@ -1814,19 +1918,19 @@ timestamp_to_char(Timestamp *dt, text *fmt) tm->tm_mday =1; tm->tm_isdst =0; tm->tm_mon =1; - if (TIMESTAMP_IS_EPOCH(*dt)) { - x = timestamp2tm(SetTimestamp(*dt), NULL, tm, &fsec, NULL); - - } else if (TIMESTAMP_IS_CURRENT(*dt)) { - x = timestamp2tm(SetTimestamp(*dt), &tz, tm, &fsec, &tzn); - - } else { - x = timestamp2tm(*dt, &tz, tm, &fsec, &tzn); - } - - if (x!=0) - elog(ERROR, "to_char(): Unable to convert timestamp to tm"); - + if (TIMESTAMP_IS_EPOCH(*dt)) { + x = timestamp2tm(SetTimestamp(*dt), NULL, tm, &fsec, NULL); + + } else if (TIMESTAMP_IS_CURRENT(*dt)) { + x = timestamp2tm(SetTimestamp(*dt), &tz, tm, &fsec, &tzn); + + } else { + x = timestamp2tm(*dt, &tz, tm, &fsec, &tzn); + } + + if (x!=0) + elog(ERROR, "to_char(): Unable to convert timestamp to tm"); + tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7; tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1,1) +1; @@ -1850,7 +1954,7 @@ timestamp_to_char(Timestamp *dt, text *fmt) * ---------- */ if ( len > DCH_CACHE_SIZE ) { - + format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); flag = 1; @@ -1865,33 +1969,29 @@ timestamp_to_char(Timestamp *dt, text *fmt) * Use cache buffers * ---------- */ -#ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "DCH_TO_CHAR() Len: %d", len); - elog(DEBUG_elog_output, "DCH_TO_CHAR() Cache - str: >%s<", CacheStr); - elog(DEBUG_elog_output, "DCH_TO_CHAR() Arg.str: >%s<", str); -#endif + DCHCacheEntry *ent; flag = 0; - if (strcmp(CacheStr, str) != 0) { + if ((ent = DCH_cache_search(str)) == NULL) { + + ent = DCH_cache_getnew(str); /* ---------- - * Can't use the cache, must run parser and save a original - * format-picture string to the cache. + * Not in the cache, must run parser and save a new + * format-picture to the cache. * ---------- */ - strncpy(CacheStr, str, DCH_CACHE_SIZE); - - parse_format(CacheFormat, str, DCH_keywords, + parse_format(ent->format, str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); - + + (ent->format + len)->type = NODE_TYPE_END; /* Paranoa? */ + #ifdef DEBUG_TO_FROM_CHAR - /* dump_node(CacheFormat, len); */ + /* dump_node(ent->format, len); */ /* dump_index(DCH_keywords, DCH_index); */ #endif - (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ - } - - format = CacheFormat; + } + format = ent->format; } DCH_processor(format, VARDATA(result), TO_CHAR); @@ -1900,7 +2000,20 @@ timestamp_to_char(Timestamp *dt, text *fmt) pfree(format); pfree(str); - VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ; + + /* ---------- + * for result is allocated max memory, which current format-picture + * needs, now it must be re-allocate to result real size + * ---------- + */ + len = strlen(VARDATA(result)); + result_tmp = result; + result = (text *) palloc( len + 1 + VARHDRSZ); + + strcpy( VARDATA(result), VARDATA(result_tmp)); + VARSIZE(result) = len + VARHDRSZ; + pfree(result_tmp); + return result; } @@ -1915,9 +2028,6 @@ timestamp_to_char(Timestamp *dt, text *fmt) Timestamp * to_timestamp(text *date_str, text *fmt) { - static FormatNode CacheFormat[ DCH_CACHE_SIZE +1]; - static char CacheStr[ DCH_CACHE_SIZE +1]; - FormatNode *format; int flag=0; Timestamp *result; @@ -1963,37 +2073,35 @@ to_timestamp(text *date_str, text *fmt) DCH_suff, DCH_index, DCH_TYPE, NULL); (format + len)->type = NODE_TYPE_END; /* Paranoa? */ - } else { - + /* ---------- * Use cache buffers * ---------- */ -#ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "DCH_TO_CHAR() Len: %d", len); - elog(DEBUG_elog_output, "DCH_TO_CHAR() Cache - str: >%s<", CacheStr); - elog(DEBUG_elog_output, "DCH_TO_CHAR() Arg.str: >%s<", str); -#endif + DCHCacheEntry *ent; flag = 0; - if (strcmp(CacheStr, str) != 0) { - + if ((ent = DCH_cache_search(str)) == NULL) { + + ent = DCH_cache_getnew(str); + /* ---------- - * Can't use the cache, must run parser and save a original - * format-picture string to the cache. + * Not in the cache, must run parser and save a new + * format-picture to the cache. * ---------- - */ - strncpy(CacheStr, str, DCH_CACHE_SIZE); - - parse_format(CacheFormat, str, DCH_keywords, - DCH_suff, DCH_index, DCH_TYPE, NULL); - - (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ - } - - format = CacheFormat; - } + */ + parse_format(ent->format, str, DCH_keywords, + DCH_suff, DCH_index, DCH_TYPE, NULL); + + (ent->format + len)->type = NODE_TYPE_END; /* Paranoa? */ +#ifdef DEBUG_TO_FROM_CHAR + /* dump_node(ent->format, len); */ + /* dump_index(DCH_keywords, DCH_index); */ +#endif + } + format = ent->format; + } /* ---------- * Call action for each node in FormatNode tree @@ -2083,16 +2191,107 @@ fill_str(char *str, int c, int max) return str; } +#define zeroize_NUM(_n) { \ + (_n)->flag = 0; \ + (_n)->lsign = 0; \ + (_n)->pre = 0; \ + (_n)->post = 0; \ + (_n)->pre_lsign_num = 0; \ + (_n)->need_locale = 0; \ + (_n)->multi = 0; \ + (_n)->zero_start = 0; \ + (_n)->zero_end = 0; \ +} + +static NUMCacheEntry * +NUM_cache_getnew( char *str ) +{ + NUMCacheEntry *ent = NULL; + + /* counter overload check - paranoa? */ + if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32) { + NUMCounter = 0; + + for(ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) + ent->age = (++NUMCounter); + } + + /* ---------- + * Cache is full - needs remove any older entry + * ---------- + */ + if (n_NUMCache > NUM_CACHE_FIELDS) { + + NUMCacheEntry *old = NUMCache+0; + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache); +#endif + + for(ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) { + if (ent->age < old->age) + old = ent; + } +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age); +#endif + strcpy(old->str, str); /* check str size before this func. */ + /* old->format fill parser */ + old->age = (++NUMCounter); + + ent = old; + + } else { +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache); +#endif + ent = NUMCache + n_NUMCache; + strcpy(ent->str, str); /* check str size before this func. */ + /* ent->format fill parser */ + ent->age = (++NUMCounter); + ++n_NUMCache; + } + + zeroize_NUM(&ent->Num); + + return ent; /* never */ +} + +static NUMCacheEntry * +NUM_cache_search( char *str ) +{ + int i = 0; + NUMCacheEntry *ent; + + /* counter overload check - paranoa? */ + if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32) { + NUMCounter = 0; + + for(ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) + ent->age = (++NUMCounter); + } + + for(ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) { + if (i == n_NUMCache) + break; + if (strcmp(ent->str, str) == 0) { + ent->age = (++NUMCounter); + return ent; + } + i++; + } + + return (NUMCacheEntry *) NULL; +} /* ---------- * Cache routine for NUM to_char version * ---------- */ static FormatNode * -NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, - NUMDesc *CacheNum, NUMDesc *Num, char *pars_str, int *flag) +NUM_cache( int len, NUMDesc *Num, char *pars_str, int *flag) { - FormatNode *format; + FormatNode *format = NULL; char *str; /* ---------- @@ -2113,86 +2312,57 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); *flag = 1; - Num->flag = 0; - Num->lsign = 0; - Num->pre = 0; - Num->post = 0; - Num->pre_lsign_num = 0; - Num->zero_start = 0; - Num->zero_end = 0; - Num->need_locale = 0; - Num->multi = 0; - + zeroize_NUM(Num); + parse_format(format, str, NUM_keywords, NULL, NUM_index, NUM_TYPE, Num); (format + len)->type = NODE_TYPE_END; /* Paranoa? */ - pfree(str); - return format; } else { - + /* ---------- - * Use cache buffer + * Use cache buffers * ---------- */ -#ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "NUM_TO_CHAR() Len: %d", len); - elog(DEBUG_elog_output, "NUM_TO_CHAR() Cache - str: >%s<", CacheStr); - elog(DEBUG_elog_output, "NUM_TO_CHAR() Arg.str: >%s<", str); -#endif - *flag = 0; + NUMCacheEntry *ent; + flag = 0; - if (strcmp(CacheStr, str) != 0) { + if ((ent = NUM_cache_search(str)) == NULL) { + + ent = NUM_cache_getnew(str); /* ---------- - * Can't use the cache, must run parser and save a original - * format-picture string to the cache. + * Not in the cache, must run parser and save a new + * format-picture to the cache. * ---------- */ - strncpy(CacheStr, str, NUM_CACHE_SIZE); - - /* ---------- - * Set zeros to CacheNum struct - * ---------- - */ - CacheNum->flag = 0; - CacheNum->lsign = 0; - CacheNum->pre = 0; - CacheNum->post = 0; - CacheNum->pre_lsign_num = 0; - CacheNum->need_locale = 0; - CacheNum->multi = 0; - CacheNum->zero_start = 0; - CacheNum->zero_end = 0; - - parse_format(CacheFormat, str, NUM_keywords, - NULL, NUM_index, NUM_TYPE, CacheNum); - -#ifdef DEBUG_TO_FROM_CHAR - /* dump_node(CacheFormat, len); */ - /* dump_index(NUM_keywords, NUM_index); */ -#endif - - (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ - } - /* ---------- + parse_format(ent->format, str, NUM_keywords, + NULL, NUM_index, NUM_TYPE, &ent->Num); + + (ent->format + len)->type = NODE_TYPE_END; /* Paranoa? */ + + } + + format = ent->format; + + /* ---------- * Copy cache to used struct * ---------- */ - Num->flag = CacheNum->flag; - Num->lsign = CacheNum->lsign; - Num->pre = CacheNum->pre; - Num->post = CacheNum->post; - Num->pre_lsign_num = CacheNum->pre_lsign_num; - Num->need_locale = CacheNum->need_locale; - Num->multi = CacheNum->multi; - Num->zero_start = CacheNum->zero_start; - Num->zero_end = CacheNum->zero_end; - - pfree(str); - return CacheFormat; + Num->flag = ent->Num.flag; + Num->lsign = ent->Num.lsign; + Num->pre = ent->Num.pre; + Num->post = ent->Num.post; + Num->pre_lsign_num = ent->Num.pre_lsign_num; + Num->need_locale = ent->Num.need_locale; + Num->multi = ent->Num.multi; + Num->zero_start = ent->Num.zero_start; + Num->zero_end = ent->Num.zero_end; } + + pfree(str); + return format; } @@ -2332,8 +2502,10 @@ get_last_relevant_decnum(char *num) { char *result, *p = strchr(num, '.'); - - /*elog(NOTICE, "CALL: get_last_relevant_decnum()");*/ + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "CALL: get_last_relevant_decnum()"); +#endif if (!p) p = num; @@ -2359,14 +2531,17 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen) elog(DEBUG_elog_output, " --- scan start --- "); #endif -#define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen) - if (*Np->inout_p == ' ') Np->inout_p++; +#define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen) + + if (*Np->inout_p == ' ') + Np->inout_p++; + if (OVERLOAD_TEST) return; - + /* ---------- * read sign * ---------- @@ -2420,7 +2595,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen) Np->inout_p++; } } - + if (OVERLOAD_TEST) return; @@ -2441,7 +2616,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int plen) #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Read digit (%c).", *Np->inout_p); -#endif +#endif /* ---------- * read decimal point @@ -3047,15 +3222,14 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, return textin(""); \ \ result = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \ - format = NUM_cache(len, CacheStr, CacheFormat, &CacheNum, &Num, \ - VARDATA(fmt), &flag); \ + format = NUM_cache(len, &Num, VARDATA(fmt), &flag); \ } /* ---------- * MACRO: Finish part of NUM * ---------- */ -#define NUM_TOCHAR_finish { \ +#define NUM_TOCHAR_finish { \ \ NUM_processor(format, &Num, VARDATA(result), \ numstr, plen, sign, TO_CHAR); \ @@ -3064,21 +3238,29 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, if (flag) \ pfree(format); \ \ - VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ; \ + /* ---------- \ + * for result is allocated max memory, which current format-picture\ + * needs, now it must be re-allocate to result real size \ + * ---------- \ + */ \ + len = strlen(VARDATA(result)); \ + result_tmp = result; \ + result = (text *) palloc( len + 1 + VARHDRSZ); \ + \ + strcpy( VARDATA(result), VARDATA(result_tmp)); \ + VARSIZE(result) = len + VARHDRSZ; \ + pfree(result_tmp); \ } /* ------------------- - * NUMERIC to_number() + * NUMERIC to_number() (convert string to numeric) * ------------------- */ Numeric numeric_to_number(text *value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; + Numeric result; FormatNode *format; char *numstr; int flag=0; @@ -3094,8 +3276,7 @@ numeric_to_number(text *value, text *fmt) if (!len) return numeric_in(NULL, 0, 0); - format = NUM_cache(len, CacheStr, CacheFormat, &CacheNum, &Num, - VARDATA(fmt), &flag); + format = NUM_cache(len, &Num, VARDATA(fmt), &flag); numstr = (char *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1); @@ -3104,8 +3285,13 @@ numeric_to_number(text *value, text *fmt) scale = Num.post; precision = MAX(0, Num.pre) + scale; + + if (flag) + pfree(format); - return numeric_in(numstr, 0, ((precision << 16) | scale) + VARHDRSZ); + result = numeric_in(numstr, 0, ((precision << 16) | scale) + VARHDRSZ); + pfree(numstr); + return result; } /* ------------------ @@ -3115,16 +3301,13 @@ numeric_to_number(text *value, text *fmt) text * numeric_to_char(Numeric value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; FormatNode *format; - text *result; + text *result, *result_tmp; int flag=0; int len=0, plen=0, sign=0; char *numstr, *orgnum, *p; + Numeric x = NULL; NUM_TOCHAR_prepare; @@ -3133,18 +3316,29 @@ numeric_to_char(Numeric value, text *fmt) * ---------- */ if (IS_ROMAN(&Num)) { - numstr = orgnum = int_to_roman( numeric_int4( numeric_round(value, 0))); + x = numeric_round(value, 0); + numstr = orgnum = int_to_roman( numeric_int4( x )); + pfree(x); } else { - Numeric val = value; + Numeric val = value; if (IS_MULTI(&Num)) { - val = numeric_mul(value, - numeric_power(int4_numeric(10), int4_numeric(Num.multi))); + Numeric a = int4_numeric(10); + Numeric b = int4_numeric(Num.multi); + + x = numeric_power(a, b); + val = numeric_mul(value, x); + pfree(x); + pfree(a); + pfree(b); Num.pre += Num.multi; } - orgnum = numeric_out( numeric_round(val, Num.post) ); + x = numeric_round(val, Num.post); + orgnum = numeric_out( x ); + pfree(x); + if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum+1; @@ -3164,7 +3358,10 @@ numeric_to_char(Numeric value, text *fmt) fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; fill_str(numstr + 1 + Num.pre, '#', Num.post); - } + } + + if (IS_MULTI(&Num)) + pfree(val); } NUM_TOCHAR_finish; @@ -3178,13 +3375,9 @@ numeric_to_char(Numeric value, text *fmt) text * int4_to_char(int32 value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; FormatNode *format; - text *result; + text *result, *result_tmp; int flag=0; int len=0, plen=0, sign=0; char *numstr, *orgnum; @@ -3247,13 +3440,9 @@ int4_to_char(int32 value, text *fmt) text * int8_to_char(int64 *value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; FormatNode *format; - text *result; + text *result, *result_tmp; int flag=0; int len=0, plen=0, sign=0; char *numstr, *orgnum; @@ -3317,13 +3506,9 @@ int8_to_char(int64 *value, text *fmt) text * float4_to_char(float32 value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; FormatNode *format; - text *result; + text *result, *result_tmp; int flag=0; int len=0, plen=0, sign=0; char *numstr, *orgnum, *p; @@ -3385,13 +3570,9 @@ float4_to_char(float32 value, text *fmt) text * float8_to_char(float64 value, text *fmt) { - static FormatNode CacheFormat[ NUM_CACHE_SIZE +1]; - static char CacheStr[ NUM_CACHE_SIZE +1]; - static NUMDesc CacheNum; - NUMDesc Num; FormatNode *format; - text *result; + text *result, *result_tmp; int flag=0; int len=0, plen=0, sign=0; char *numstr, *orgnum, *p;