mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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
This commit is contained in:
parent
6358e654ca
commit
4a3a1e2cf1
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user