11/* -----------------------------------------------------------------------
22 * formatting.c
33 *
4- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.26 2000/12/03 20:45:35 tgl Exp $
4+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.27 2000/12/15 19:15:09 momjian Exp $
55 *
66 *
77 * Portions Copyright (c) 1999-2000, PostgreSQL, Inc
4444 *
4545 * Karel Zak
4646 *
47+ * TODO (7.2):
48+ * - replace some global values by struct that handle it
49+ * - check last used entry in the cache_search
50+ * - better number building (formatting)
51+ * - add support for abstime
52+ * - add support for roman number to standard number conversion
53+ * - add support for number spelling
54+ * - add support for string to string formatting (we must be better
55+ * than Oracle :-),
56+ * to_char('Hello', 'X X X X X') -> 'H e l l o'
57+ *
4758 * -----------------------------------------------------------------------
4859 */
4960
@@ -334,11 +345,12 @@ static int DCHCounter = 0;
334345
335346/* global cache for --- number part */
336347static NUMCacheEntry NUMCache [NUM_CACHE_FIELDS + 1 ];
348+ static NUMCacheEntry * last_NUMCacheEntry ;
337349
338350static int n_NUMCache = 0 ; /* number of entries */
339351static int NUMCounter = 0 ;
340352
341- #define MAX_INT32 (2147483640 )
353+ #define MAX_INT32 (2147483600 )
342354
343355/* ----------
344356 * For char->date/time conversion
@@ -850,8 +862,10 @@ static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *nu
850862 int plen , int sign , int type );
851863static DCHCacheEntry * DCH_cache_search (char * str );
852864static DCHCacheEntry * DCH_cache_getnew (char * str );
865+
853866static NUMCacheEntry * NUM_cache_search (char * str );
854867static NUMCacheEntry * NUM_cache_getnew (char * str );
868+ static void NUM_cache_remove (NUMCacheEntry * ent );
855869
856870
857871/* ----------
@@ -917,8 +931,10 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
917931
918932 case NUM_9 :
919933 if (IS_BRACKET (num ))
934+ {
935+ NUM_cache_remove (last_NUMCacheEntry );
920936 elog (ERROR , "to_char/to_number(): '9' must be ahead of 'PR'." );
921-
937+ }
922938 if (IS_MULTI (num ))
923939 {
924940 ++ num -> multi ;
@@ -932,8 +948,10 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
932948
933949 case NUM_0 :
934950 if (IS_BRACKET (num ))
951+ {
952+ NUM_cache_remove (last_NUMCacheEntry );
935953 elog (ERROR , "to_char/to_number(): '0' must be ahead of 'PR'." );
936-
954+ }
937955 if (!IS_ZERO (num ) && !IS_DECIMAL (num ))
938956 {
939957 num -> flag |= NUM_F_ZERO ;
@@ -957,9 +975,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
957975 num -> need_locale = TRUE;
958976 case NUM_DEC :
959977 if (IS_DECIMAL (num ))
978+ {
979+ NUM_cache_remove (last_NUMCacheEntry );
960980 elog (ERROR , "to_char/to_number(): not unique decimal poit." );
981+ }
961982 if (IS_MULTI (num ))
983+ {
984+ NUM_cache_remove (last_NUMCacheEntry );
962985 elog (ERROR , "to_char/to_number(): can't use 'V' and decimal poin together." );
986+ }
963987 num -> flag |= NUM_F_DECIMAL ;
964988 break ;
965989
@@ -969,11 +993,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
969993
970994 case NUM_S :
971995 if (IS_LSIGN (num ))
996+ {
997+ NUM_cache_remove (last_NUMCacheEntry );
972998 elog (ERROR , "to_char/to_number(): not unique 'S'." );
973-
999+ }
9741000 if (IS_PLUS (num ) || IS_MINUS (num ) || IS_BRACKET (num ))
1001+ {
1002+ NUM_cache_remove (last_NUMCacheEntry );
9751003 elog (ERROR , "to_char/to_number(): can't use 'S' and 'PL'/'MI'/'SG'/'PR' together." );
976-
1004+ }
9771005 if (!IS_DECIMAL (num ))
9781006 {
9791007 num -> lsign = NUM_LSIGN_PRE ;
@@ -992,29 +1020,38 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
9921020
9931021 case NUM_MI :
9941022 if (IS_LSIGN (num ))
1023+ {
1024+ NUM_cache_remove (last_NUMCacheEntry );
9951025 elog (ERROR , "to_char/to_number(): can't use 'S' and 'MI' together." );
996-
1026+ }
9971027 num -> flag |= NUM_F_MINUS ;
9981028 break ;
9991029
10001030 case NUM_PL :
10011031 if (IS_LSIGN (num ))
1032+ {
1033+ NUM_cache_remove (last_NUMCacheEntry );
10021034 elog (ERROR , "to_char/to_number(): can't use 'S' and 'PL' together." );
1003-
1035+ }
10041036 num -> flag |= NUM_F_PLUS ;
10051037 break ;
10061038
10071039 case NUM_SG :
10081040 if (IS_LSIGN (num ))
1041+ {
1042+ NUM_cache_remove (last_NUMCacheEntry );
10091043 elog (ERROR , "to_char/to_number(): can't use 'S' and 'SG' together." );
1010-
1044+ }
10111045 num -> flag |= NUM_F_MINUS ;
10121046 num -> flag |= NUM_F_PLUS ;
10131047 break ;
10141048
10151049 case NUM_PR :
10161050 if (IS_LSIGN (num ) || IS_PLUS (num ) || IS_MINUS (num ))
1051+ {
1052+ NUM_cache_remove (last_NUMCacheEntry );
10171053 elog (ERROR , "to_char/to_number(): can't use 'PR' and 'S'/'PL'/'MI'/'SG' together." );
1054+ }
10181055 num -> flag |= NUM_F_BRACKET ;
10191056 break ;
10201057
@@ -1030,11 +1067,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
10301067
10311068 case NUM_V :
10321069 if (IS_DECIMAL (num ))
1070+ {
1071+ NUM_cache_remove (last_NUMCacheEntry );
10331072 elog (ERROR , "to_char/to_number(): can't use 'V' and decimal poin together." );
1073+ }
10341074 num -> flag |= NUM_F_MULTI ;
10351075 break ;
10361076
10371077 case NUM_E :
1078+ NUM_cache_remove (last_NUMCacheEntry );
10381079 elog (ERROR , "to_char/to_number(): 'E' is not supported." );
10391080 }
10401081
@@ -2988,6 +3029,14 @@ NUM_cache_getnew(char *str)
29883029
29893030 for (ent = NUMCache ; ent <= (NUMCache + NUM_CACHE_FIELDS ); ent ++ )
29903031 {
3032+ /* entry removed via NUM_cache_remove()
3033+ * can be used here
3034+ */
3035+ if (* ent -> str == '\0' )
3036+ {
3037+ old = ent ;
3038+ break ;
3039+ }
29913040 if (ent -> age < old -> age )
29923041 old = ent ;
29933042 }
@@ -3015,6 +3064,7 @@ NUM_cache_getnew(char *str)
30153064
30163065 zeroize_NUM (& ent -> Num );
30173066
3067+ last_NUMCacheEntry = ent ;
30183068 return ent ; /* never */
30193069}
30203070
@@ -3040,6 +3090,7 @@ NUM_cache_search(char *str)
30403090 if (strcmp (ent -> str , str ) == 0 )
30413091 {
30423092 ent -> age = (++ NUMCounter );
3093+ last_NUMCacheEntry = ent ;
30433094 return ent ;
30443095 }
30453096 i ++ ;
@@ -3048,6 +3099,16 @@ NUM_cache_search(char *str)
30483099 return (NUMCacheEntry * ) NULL ;
30493100}
30503101
3102+ static void
3103+ NUM_cache_remove (NUMCacheEntry * ent )
3104+ {
3105+ #ifdef DEBUG_TO_FROM_CHAR
3106+ elog (DEBUG_elog_output , "REMOVING ENTRY (%s)" , ent -> str );
3107+ #endif
3108+ * ent -> str = '\0' ;
3109+ ent -> age = 0 ;
3110+ }
3111+
30513112/* ----------
30523113 * Cache routine for NUM to_char version
30533114 * ----------
@@ -3070,7 +3131,7 @@ NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag)
30703131 * Allocate new memory if format picture is bigger than static cache
30713132 * and not use cache (call parser always) - flag=1 show this variant
30723133 * ----------
3073- */
3134+ */
30743135 if (len > NUM_CACHE_SIZE )
30753136 {
30763137
0 commit comments