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 intDCHCounter = 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
850862int 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
918932case NUM_9 :
919933if (IS_BRACKET (num ))
934+ {
935+ NUM_cache_remove (last_NUMCacheEntry );
920936elog (ERROR ,"to_char/to_number(): '9' must be ahead of 'PR'." );
921-
937+ }
922938if (IS_MULTI (num ))
923939{
924940++ num -> multi ;
@@ -932,8 +948,10 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
932948
933949case NUM_0 :
934950if (IS_BRACKET (num ))
951+ {
952+ NUM_cache_remove (last_NUMCacheEntry );
935953elog (ERROR ,"to_char/to_number(): '0' must be ahead of 'PR'." );
936-
954+ }
937955if (!IS_ZERO (num )&& !IS_DECIMAL (num ))
938956{
939957num -> flag |=NUM_F_ZERO ;
@@ -957,9 +975,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
957975num -> need_locale = TRUE;
958976case NUM_DEC :
959977if (IS_DECIMAL (num ))
978+ {
979+ NUM_cache_remove (last_NUMCacheEntry );
960980elog (ERROR ,"to_char/to_number(): not unique decimal poit." );
981+ }
961982if (IS_MULTI (num ))
983+ {
984+ NUM_cache_remove (last_NUMCacheEntry );
962985elog (ERROR ,"to_char/to_number(): can't use 'V' and decimal poin together." );
986+ }
963987num -> flag |=NUM_F_DECIMAL ;
964988break ;
965989
@@ -969,11 +993,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
969993
970994case NUM_S :
971995if (IS_LSIGN (num ))
996+ {
997+ NUM_cache_remove (last_NUMCacheEntry );
972998elog (ERROR ,"to_char/to_number(): not unique 'S'." );
973-
999+ }
9741000if (IS_PLUS (num )|| IS_MINUS (num )|| IS_BRACKET (num ))
1001+ {
1002+ NUM_cache_remove (last_NUMCacheEntry );
9751003elog (ERROR ,"to_char/to_number(): can't use 'S' and 'PL'/'MI'/'SG'/'PR' together." );
976-
1004+ }
9771005if (!IS_DECIMAL (num ))
9781006{
9791007num -> lsign = NUM_LSIGN_PRE ;
@@ -992,29 +1020,38 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
9921020
9931021case NUM_MI :
9941022if (IS_LSIGN (num ))
1023+ {
1024+ NUM_cache_remove (last_NUMCacheEntry );
9951025elog (ERROR ,"to_char/to_number(): can't use 'S' and 'MI' together." );
996-
1026+ }
9971027num -> flag |=NUM_F_MINUS ;
9981028break ;
9991029
10001030case NUM_PL :
10011031if (IS_LSIGN (num ))
1032+ {
1033+ NUM_cache_remove (last_NUMCacheEntry );
10021034elog (ERROR ,"to_char/to_number(): can't use 'S' and 'PL' together." );
1003-
1035+ }
10041036num -> flag |=NUM_F_PLUS ;
10051037break ;
10061038
10071039case NUM_SG :
10081040if (IS_LSIGN (num ))
1041+ {
1042+ NUM_cache_remove (last_NUMCacheEntry );
10091043elog (ERROR ,"to_char/to_number(): can't use 'S' and 'SG' together." );
1010-
1044+ }
10111045num -> flag |=NUM_F_MINUS ;
10121046num -> flag |=NUM_F_PLUS ;
10131047break ;
10141048
10151049case NUM_PR :
10161050if (IS_LSIGN (num )|| IS_PLUS (num )|| IS_MINUS (num ))
1051+ {
1052+ NUM_cache_remove (last_NUMCacheEntry );
10171053elog (ERROR ,"to_char/to_number(): can't use 'PR' and 'S'/'PL'/'MI'/'SG' together." );
1054+ }
10181055num -> flag |=NUM_F_BRACKET ;
10191056break ;
10201057
@@ -1030,11 +1067,15 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
10301067
10311068case NUM_V :
10321069if (IS_DECIMAL (num ))
1070+ {
1071+ NUM_cache_remove (last_NUMCacheEntry );
10331072elog (ERROR ,"to_char/to_number(): can't use 'V' and decimal poin together." );
1073+ }
10341074num -> flag |=NUM_F_MULTI ;
10351075break ;
10361076
10371077case NUM_E :
1078+ NUM_cache_remove (last_NUMCacheEntry );
10381079elog (ERROR ,"to_char/to_number(): 'E' is not supported." );
10391080}
10401081
@@ -2988,6 +3029,14 @@ NUM_cache_getnew(char *str)
29883029
29893030for (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+ }
29913040if (ent -> age < old -> age )
29923041old = ent ;
29933042}
@@ -3015,6 +3064,7 @@ NUM_cache_getnew(char *str)
30153064
30163065zeroize_NUM (& ent -> Num );
30173066
3067+ last_NUMCacheEntry = ent ;
30183068return ent ;/* never */
30193069}
30203070
@@ -3040,6 +3090,7 @@ NUM_cache_search(char *str)
30403090if (strcmp (ent -> str ,str )== 0 )
30413091{
30423092ent -> age = (++ NUMCounter );
3093+ last_NUMCacheEntry = ent ;
30433094return ent ;
30443095}
30453096i ++ ;
@@ -3048,6 +3099,16 @@ NUM_cache_search(char *str)
30483099return (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+ */
30743135if (len > NUM_CACHE_SIZE )
30753136{
30763137