Hi,
authorBruce Momjian <bruce@momjian.us>
Thu, 16 Mar 2000 01:35:41 +0000 (01:35 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 16 Mar 2000 01:35:41 +0000 (01:35 +0000)
 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

index c324014669de523ac18c88a2ddbbc701db6b69f5..2bd3f016a7471a25bb2a8591e4793fedc4208585 100644 (file)
@@ -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
  *
  *
  *   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:
  * 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;