From: Bruce Momjian Date: Tue, 8 Feb 2000 15:57:01 +0000 (+0000) Subject: I'm sending patch with new version of to_char numbers formatting. X-Git-Tag: REL7_0~677 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=394af52795f6bb02ae26af2ddca6cec0f255ee33;p=postgresql I'm sending patch with new version of to_char numbers formatting. The PostgreSQL's to_char() is very compatible with Oracle's to_char now. I hope that to_char's 3000 rows of source is without bugs, but will good if anyone test it, for me it works very well :-) Karel ---------------------------------------------------------------------- Karel Zak http://home.zf.jcu.cz/~zakkr/ --- diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 55cadab445..5c7529b729 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -518,7 +518,7 @@ - Format-pictures for datetime to_char() version. + Format-pictures for date/time to_char() version. @@ -662,12 +662,12 @@ All format-pictures allow use suffixes (postfix / prefix). The suffix is - always valid for near format-picture. The 'FX' is global prefix only. + always valid for a near format-picture. The 'FX' is global prefix only.
- Suffixes for format-pictures for datetime to_char() version. + Suffixes for format-pictures for date/time to_char() version. @@ -695,7 +695,7 @@ FX FX - (Fixed format) global format-picture switch. - the TO_DATETIME / TO_DATA skip blank space if this option is + The TO_DATETIME / TO_DATE skip blank space if this option is not use. Must by used as first item in formt-picture. FX Month DD Day @@ -714,7 +714,7 @@ '"' - string between a quotation marks is skipen and not is parsed. - If you want write '"' to output you must use \\", exapmle '\\"YYYY Month\\"'. + If you want write '"' to output you must use \\", example '\\"YYYY Month\\"'. text - the PostgreSQL's to_char() support text without '"', but string @@ -776,7 +776,11 @@ PL - return plus sign on specified position (if number > 0) + return plus sign on specified position (if number > 0) - PostgreSQL extension + + + SG + return plus/minus sign on specified position - PostgreSQL extension RN @@ -784,7 +788,7 @@ TH or th - convert number to ordinal number (not convert numbers under zero and decimal numbers) + convert number to ordinal number (not convert numbers under zero and decimal numbers) - PostgreSQL extension V @@ -801,9 +805,12 @@ - The PostgreSQL to_char() not support absurd to_char(0.1, '99.99') - --> ' .10' format. - + Note: A sign formatted via 'SG', 'PL' or 'MI' is not anchor in number; + to_char(-12, 'S9999') produce: ' -12' , + but to_char(-12, 'MI9999') produce: '- 12' . + The Oracle not allow use 'MI' ahead of '9', in the Oracle must be it always + after '9'. +
@@ -825,16 +832,24 @@ 'Tuesday, 05:39:18' - to_char( 0.1, '99.99') - ' 0.10' + to_char( -0.1, '99.99') + ' -.10' + + + to_char( -0.1, 'FM9.99') + '-.1' to_char( 0.1, '0.9') ' 0.1' - to_char( 0.1, '090.9') - ' 000.1' + to_char( 12, '9990999.9') + ' 0012.0' + + + to_char( 12, 'FM9990999.9') + '0012' to_char( 485, '999') @@ -844,18 +859,6 @@ to_char( -485, '999') '-485' - - to_char( 485, '09999') - ' 00485' - - - to_char( 485, 'FM09999') - '00485' - - - to_char( 485, 'FM999') - '485' - to_char( 485, '9 9 9') ' 4 8 5' diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 3a5a942f05..e8f6d2cd47 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,15 +1,17 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.2 2000/01/26 06:33:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.3 2000/02/08 15:56:55 momjian Exp $ + * + * + * Portions Copyright (c) 1999-2000, PostgreSQL, Inc + * * * TO_CHAR(); TO_DATETIME(); TO_DATE(); TO_NUMBER(); * * The PostgreSQL routines for a DateTime/int/float/numeric formatting, * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * - * 1999 Karel Zak "Zakkr" - * * * Cache & Memory: * Routines use (itself) internal cache for format pictures. If @@ -33,13 +35,16 @@ * * Supported types for to_char(): * - * DateTime, Numeric, int4, int8, float4, float8 + * Timestamp, DateTime, Numeric, int4, int8, float4, float8 * * Supported types for reverse conversion: * * Datetime - to_datetime() * Date - to_date() * Numeric - to_number() + * + * + * Karel Zak - Zakkr * * ----------------------------------------------------------------------- */ @@ -106,8 +111,8 @@ * External (defined in PgSQL dt.c (datetime utils)) * ---------- */ -extern char *months[], /* month abbreviation */ - *days[]; /* full days */ +extern char *months[], /* month abbreviation */ + *days[]; /* full days */ /* ---------- * Format parser structs @@ -231,11 +236,13 @@ static int DCH_global_flag = 0; */ typedef struct { int pre, /* (count) numbers before decimal */ - pos, /* (count) numbers after decimal */ + post, /* (count) numbers after decimal */ lsign, /* want locales sign */ flag, /* number parametrs */ pre_lsign_num, /* tmp value for lsign */ multi, /* multiplier for 'V' */ + zero_start, /* position of first zero */ + zero_end, /* position of last zero */ need_locale; /* needs it locale */ } NUMDesc; @@ -270,6 +277,7 @@ typedef struct { #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE) #define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET) #define IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS) +#define IS_LSIGN(_f) ((_f)->flag & NUM_F_LSIGN) #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS) #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN) #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI) @@ -350,12 +358,13 @@ static KeySuffix DCH_suff[] = { * Position for the keyword is simular as position in the enum DCH/NUM_poz * (!) * - * For fast search is used the 'int index[256-32]' (first 32 ascii chars is - * skiped), in this index is DCH_ enums for each ASCII position or -1 if - * char is not used in the KeyWord. Search example for string "MM": - * 1) see in index to index[77-32] (77 = 'M'), - * 2) take keywords position from index[77-32] - * 3) run sequential search in keywords[] from position + * For fast search is used the 'int index[]', index is ascii table from position + * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII + * position or -1 if char is not used in the KeyWord. Search example for + * string "MM": + * 1) see in index to index['M' - 32], + * 2) take keywords position (enum DCH_MM) from index + * 3) run sequential search in keywords[] from this position * * ---------- */ @@ -512,7 +521,7 @@ static int DCH_index[256 - 32] = { /* 0 1 2 3 4 5 6 7 8 9 */ - /*---- first 0..31 chars is skiped ----*/ + /*---- first 0..31 chars are skiped ----*/ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -562,18 +571,24 @@ typedef struct NUMProc { int type; /* FROM_CHAR (TO_NUMBER) or TO_CHAR */ - NUMDesc *Num; /* number description */ + NUMDesc *Num; /* number description */ + + int sign, /* '-' or '+' */ + sign_wrote, /* was sign write */ + sign_pos, /* pre number sign position */ + num_count, /* number of write digits */ + num_in, /* is inside number */ + num_curr, /* current position in number */ + num_pre, /* space before first number */ - int sign, /* '-' or '+' */ - sign_wrote, /* is sign wrote */ - count_num, /* number of non-write digits */ - in_number, /* is inside number */ - pre_number; /* space before number */ + read_dec, /* to_number - was read dec. point */ + read_post; /* to_number - number of dec. digit */ char *number, /* string with number */ *number_p, /* pointer to current number pozition */ *inout, /* in / out buffer */ *inout_p, /* pointer to current inout pozition */ + *last_relevant, /* last relevant number after decimal point */ *L_negative_sign, /* Locale */ *L_positive_sign, @@ -592,7 +607,7 @@ static KeySuffix *suff_search(char *str, KeySuffix *suf, int type); static void NUMDesc_prepare(NUMDesc *num, FormatNode *n); static void parse_format(FormatNode *node, char *str, KeyWord *kw, KeySuffix *suf, int *index, int ver, NUMDesc *Num); -static char *DCH_action(FormatNode *node, char *inout, int flag); +static char *DCH_processor(FormatNode *node, char *inout, int flag); #ifdef DEBUG_TO_FROM_CHAR static void dump_index(KeyWord *k, int *index); @@ -614,7 +629,9 @@ static FormatNode *NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, NUMDesc *CacheNum, NUMDesc *Num, char *pars_str, int *flag); static char *int_to_roman(int number); static void NUM_prepare_locale(NUMProc *Np); -static int NUM_numpart(NUMProc *Np, int id); +static char *get_last_relevant_decnum(char *num); +static void NUM_numpart_from_char(NUMProc *Np, int id); +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); @@ -677,27 +694,37 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) switch(n->key->id) { case NUM_9: + if (IS_BRACKET(num)) + elog(ERROR, "to_char/to_number(): '9' must be ahead of 'PR'."); + if (IS_MULTI(num)) { ++num->multi; break; } if (IS_DECIMAL(num)) - ++num->pos; + ++num->post; else ++num->pre; break; case NUM_0: - if (num->pre == 0) + if (IS_BRACKET(num)) + elog(ERROR, "to_char/to_number(): '0' must be ahead of 'PR'."); + + if (!IS_ZERO(num) && !IS_DECIMAL(num)) { num->flag |= NUM_F_ZERO; + num->zero_start = num->pre + 1; + } if (! IS_DECIMAL(num)) ++num->pre; else - ++num->pos; + ++num->post; + + num->zero_end = num->pre + num->post; break; case NUM_B: - if (num->pre == 0 && num->pos == 0 && (! IS_ZERO(num))) + if (num->pre == 0 && num->post == 0 && (! IS_ZERO(num))) num->flag |= NUM_F_BLANK; break; @@ -706,9 +733,9 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) num->need_locale = TRUE; case NUM_DEC: if (IS_DECIMAL(num)) - elog(ERROR, "to_char/number(): not unique decimal poit."); + elog(ERROR, "to_char/to_number(): not unique decimal poit."); if (IS_MULTI(num)) - elog(ERROR, "to_char/number(): can't use 'V' and decimal poin together."); + elog(ERROR, "to_char/to_number(): can't use 'V' and decimal poin together."); num->flag |= NUM_F_DECIMAL; break; @@ -717,33 +744,53 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) break; case NUM_S: + if (IS_LSIGN(num)) + elog(ERROR, "to_char/to_number(): not unique 'S'."); + + if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num)) + elog(ERROR, "to_char/to_number(): can't use 'S' and 'PL'/'MI'/'SG'/'PR' together."); + if (! IS_DECIMAL(num)) { num->lsign = NUM_LSIGN_PRE; num->pre_lsign_num = num->pre; - num->need_locale = TRUE; + num->need_locale = TRUE; + num->flag |= NUM_F_LSIGN; } else if (num->lsign == NUM_LSIGN_NONE) { num->lsign = NUM_LSIGN_POST; num->need_locale = TRUE; + num->flag |= NUM_F_LSIGN; } break; case NUM_MI: + if (IS_LSIGN(num)) + elog(ERROR, "to_char/to_number(): can't use 'S' and 'MI' together."); + num->flag |= NUM_F_MINUS; break; case NUM_PL: + if (IS_LSIGN(num)) + elog(ERROR, "to_char/to_number(): can't use 'S' and 'PL' together."); + num->flag |= NUM_F_PLUS; break; case NUM_SG: + if (IS_LSIGN(num)) + elog(ERROR, "to_char/to_number(): can't use 'S' and 'SG' together."); + num->flag |= NUM_F_MINUS; num->flag |= NUM_F_PLUS; break; case NUM_PR: + if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num)) + elog(ERROR, "to_char/to_number(): can't use 'PR' and 'S'/'PL'/'MI'/'SG' together."); num->flag |= NUM_F_BRACKET; break; + case NUM_rn: case NUM_RN: num->flag |= NUM_F_ROMAN; @@ -756,9 +803,12 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) case NUM_V: if (IS_DECIMAL(num)) - elog(ERROR, "to_char/number(): can't use 'V' and decimal poin together."); + elog(ERROR, "to_char/to_number(): can't use 'V' and decimal poin together."); num->flag |= NUM_F_MULTI; break; + + case NUM_E: + elog(ERROR, "to_char/to_number(): 'E' is not supported."); } return; @@ -782,7 +832,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw, last=0; #ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "to-from_char(): run parser."); + elog(DEBUG_elog_output, "to_char/number(): run parser."); #endif n = node; @@ -895,7 +945,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw, * ---------- */ static char * -DCH_action(FormatNode *node, char *inout, int flag) +DCH_processor(FormatNode *node, char *inout, int flag) { FormatNode *n; char *s; @@ -919,7 +969,7 @@ DCH_action(FormatNode *node, char *inout, int flag) len = n->key->action(n->key->id, s, n->suffix, flag, n); if (len > 0) s += len; - else + else if (len == -1) continue; } else { @@ -972,8 +1022,8 @@ dump_node(FormatNode *node, int max) for(a=0, n=node; a<=max; n++, a++) { if (n->type == NODE_TYPE_ACTION) - elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION\t(%s,%s)", - a, DUMP_THth(n->suffix), DUMP_FM(n->suffix)); + elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)", + a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix)); else if (n->type == NODE_TYPE_CHAR) elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character); else if (n->type == NODE_TYPE_END) { @@ -1221,7 +1271,7 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node) DCH_global_flag |= DCH_F_FX; break; } - return 0; + return -1; } /* ---------- @@ -1245,8 +1295,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) tm->tm_hour <13 ? tm->tm_hour : tm->tm_hour-12); if (S_THth(suf)) str_numth(p_inout, inout, 0); - if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + if (S_FM(suf) || S_THth(suf)) + return strlen(p_inout)-1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_hour); @@ -1255,15 +1308,18 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) sscanf(inout, "%02d", &tm->tm_hour); return 1 + SKIP_THth(suf); } - } + case DCH_HH24: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour); if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + if (S_FM(suf) || S_THth(suf)) + return strlen(p_inout) -1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_hour); @@ -1273,13 +1329,17 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) return 1 + SKIP_THth(suf); } } + case DCH_MI: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_min); if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + if (S_FM(suf) || S_THth(suf)) + return strlen(p_inout)-1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_min); @@ -1294,8 +1354,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_sec); if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + if (S_FM(suf) || S_THth(suf)) + return strlen(p_inout) -1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_sec); @@ -1314,14 +1377,14 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: SSSS is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): SSSS is not supported"); } - return 0; + return -1; } #define CHECK_SEQ_SEARCH(_l, _s) { \ if (_l <= 0) { \ - elog(ERROR, "to_datatime: bad value for %s", _s); \ + elog(ERROR, "to_datatime()/to_timestamp(): bad value for %s", _s); \ } \ } @@ -1382,28 +1445,40 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) case DCH_MONTH: strcpy(inout, months_full[ tm->tm_mon - 1]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout)); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_Month: sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_month: sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]); *inout = tolower(*inout); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_MON: strcpy(inout, months[ tm->tm_mon -1 ]); inout = str_toupper(inout); return 2; + case DCH_Mon: strcpy(inout, months[ tm->tm_mon -1 ]); return 2; + case DCH_mon: strcpy(inout, months[ tm->tm_mon -1 ]); *inout = tolower(*inout); return 2; + case DCH_MM: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mon ); @@ -1411,7 +1486,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_mon); @@ -1419,33 +1496,46 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) } else { sscanf(inout, "%02d", &tm->tm_mon); return 1 + SKIP_THth(suf); - } + } } + case DCH_DAY: strcpy(inout, days[ tm->tm_wday ]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout)); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_Day: sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_day: sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]); *inout = tolower(*inout); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 8; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 8; + case DCH_DY: strcpy(inout, days[ tm->tm_wday]); inout = str_toupper(inout); return 2; + case DCH_Dy: strcpy(inout, days[ tm->tm_wday]); return 2; + case DCH_dy: strcpy(inout, days[ tm->tm_wday]); *inout = tolower(*inout); return 2; + case DCH_DDD: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, tm->tm_yday); @@ -1454,6 +1544,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; else return 2; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_yday); @@ -1463,6 +1554,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) return 2 + SKIP_THth(suf); } } + case DCH_DD: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mday); @@ -1470,7 +1562,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + else + return 1; + } else if (flag == FROM_CHAR) { if (S_FM(suf)) { sscanf(inout, "%d", &tm->tm_mday); @@ -1483,16 +1577,17 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) case DCH_D: if (flag == TO_CHAR) { sprintf(inout, "%d", tm->tm_wday+1); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 2; + } return 0; } else if (flag == FROM_CHAR) { sscanf(inout, "%1d", &tm->tm_wday); if(tm->tm_wday) --tm->tm_wday; return 0 + SKIP_THth(suf); } + case DCH_WW: if (flag == TO_CHAR) { sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, @@ -1501,19 +1596,23 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; - else return 1; + else + return 1; + } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: WW is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): WW is not supported"); case DCH_Q: if (flag == TO_CHAR) { sprintf(inout, "%d", (tm->tm_mon-1)/3+1); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 2; + } return 0; + } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: Q is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): Q is not supported"); + case DCH_CC: if (flag == TO_CHAR) { i = tm->tm_year/100 +1; @@ -1524,8 +1623,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) if (S_THth(suf)) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; + } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: CC is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): CC is not supported"); case DCH_Y_YYY: if (flag == TO_CHAR) { i= YEAR_ABS(tm->tm_year) / 1000; @@ -1535,6 +1635,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) if (tm->tm_year < 0) strcat(inout, BC_STR); return strlen(p_inout)-1; + } else if (flag == FROM_CHAR) { int cc, yy; sscanf(inout, "%d,%03d", &cc, &yy); @@ -1552,6 +1653,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) tm->tm_year = tm->tm_year+1; return len-1; } + case DCH_YYYY: if (flag == TO_CHAR) { if (tm->tm_year <= 9999 && tm->tm_year >= -9998) @@ -1563,6 +1665,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) if (tm->tm_year < 0) strcat(inout, BC_STR); return strlen(p_inout)-1; + } else if (flag == FROM_CHAR) { sscanf(inout, "%d", &tm->tm_year); if (!S_FM(suf) && tm->tm_year <= 9999 && tm->tm_year >= -9999) @@ -1577,73 +1680,92 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) tm->tm_year = tm->tm_year+1; return len-1; } + case DCH_YYY: if (flag == TO_CHAR) { sprintf(buff, "%03d", YEAR_ABS(tm->tm_year)); i=strlen(buff); strcpy(inout, buff+(i-3)); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 4; + return 4; + } return 2; + } else if (flag == FROM_CHAR) { int yy; sscanf(inout, "%03d", &yy); tm->tm_year = (tm->tm_year/1000)*1000 +yy; return 2 + SKIP_THth(suf); - } + } + case DCH_YY: if (flag == TO_CHAR) { sprintf(buff, "%02d", YEAR_ABS(tm->tm_year)); i=strlen(buff); strcpy(inout, buff+(i-2)); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 3; + return 3; + } return 1; + } else if (flag == FROM_CHAR) { int yy; sscanf(inout, "%02d", &yy); tm->tm_year = (tm->tm_year/100)*100 +yy; return 1 + SKIP_THth(suf); } + case DCH_Y: if (flag == TO_CHAR) { sprintf(buff, "%1d", YEAR_ABS(tm->tm_year)); i=strlen(buff); strcpy(inout, buff+(i-1)); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 2; + return 2; + } return 0; + } else if (flag == FROM_CHAR) { int yy; sscanf(inout, "%1d", &yy); tm->tm_year = (tm->tm_year/10)*10 +yy; return 0 + SKIP_THth(suf); } + case DCH_RM: if (flag == TO_CHAR) { sprintf(inout, "%*s", S_FM(suf) ? 0 : -4, rm_months[ 12 - tm->tm_mon ]); - if (S_FM(suf)) return strlen(p_inout)-1; - else return 3; + if (S_FM(suf)) + return strlen(p_inout)-1; + else + return 3; + } else if (flag == FROM_CHAR) { tm->tm_mon = 11-seq_search(inout, rm_months, ALL_UPPER, FULL_SIZ, &len); CHECK_SEQ_SEARCH(len, "RM"); ++tm->tm_mon; - if (S_FM(suf)) return len-1; - else return 3; + if (S_FM(suf)) + return len-1; + else + return 3; } + case DCH_W: if (flag == TO_CHAR) { sprintf(inout, "%d", (tm->tm_mday - tm->tm_wday +7) / 7 ); - if (S_THth(suf)) + if (S_THth(suf)) { str_numth(p_inout, inout, S_TH_TYPE(suf)); - if (S_THth(suf)) return 2; + return 2; + } return 0; + } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: W is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): W is not supported"); + case DCH_J: if (flag == TO_CHAR) { sprintf(inout, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); @@ -1651,9 +1773,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) str_numth(p_inout, inout, S_TH_TYPE(suf)); return strlen(p_inout)-1; } else if (flag == FROM_CHAR) - elog(ERROR, "to_datatime: J is not supported"); + elog(ERROR, "to_datatime()/to_timestamp(): J is not supported"); } - return 0; + return -1; } /**************************************************************************** @@ -1699,7 +1821,7 @@ datetime_to_char(DateTime *dt, text *fmt) datetime2tm(SetDateTime(*dt), &tz, tm, &fsec, &tzn); } else { if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) != 0) - elog(ERROR, "to_char: Unable to convert datetime to tm"); + elog(ERROR, "to_char(): Unable to convert datetime to tm"); } tm->tm_wday = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1) % 7; @@ -1756,20 +1878,20 @@ datetime_to_char(DateTime *dt, text *fmt) */ strncpy(CacheStr, str, DCH_CACHE_SIZE); + parse_format(CacheFormat, str, DCH_keywords, + DCH_suff, DCH_index, DCH_TYPE, NULL); + #ifdef DEBUG_TO_FROM_CHAR /* dump_node(CacheFormat, len); */ /* dump_index(DCH_keywords, DCH_index); */ #endif - parse_format(CacheFormat, str, DCH_keywords, - DCH_suff, DCH_index, DCH_TYPE, NULL); - (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ } format = CacheFormat; } - DCH_action(format, VARDATA(result), TO_CHAR); + DCH_processor(format, VARDATA(result), TO_CHAR); if (flag) pfree(format); @@ -1888,7 +2010,7 @@ to_datetime(text *date_str, text *fmt) /* dump_node(format, len); */ #endif VARDATA(date_str)[ VARSIZE(date_str) - VARHDRSZ ] = '\0'; - DCH_action(format, VARDATA(date_str), FROM_CHAR); + DCH_processor(format, VARDATA(date_str), FROM_CHAR); pfree(str); @@ -1939,7 +2061,7 @@ to_datetime(text *date_str, text *fmt) NOTICE_TM; #endif if (tm2datetime(tm, fsec, &tz, result) != 0) - elog(ERROR, "to_datatime: can't convert 'tm' to datetime."); + elog(ERROR, "to_datatime()/to_timestamp(): can't convert 'tm' to datetime."); return result; } @@ -2012,9 +2134,13 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, Num->flag = 0; Num->lsign = 0; Num->pre = 0; - Num->pos = 0; + Num->post = 0; Num->pre_lsign_num = 0; - + Num->zero_start = 0; + Num->zero_end = 0; + Num->need_locale = 0; + Num->multi = 0; + parse_format(format, str, NUM_keywords, NULL, NUM_index, NUM_TYPE, Num); @@ -2051,17 +2177,20 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, CacheNum->flag = 0; CacheNum->lsign = 0; CacheNum->pre = 0; - CacheNum->pos = 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 - parse_format(CacheFormat, str, NUM_keywords, - NULL, NUM_index, NUM_TYPE, CacheNum); +#endif (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ } @@ -2072,10 +2201,12 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, Num->flag = CacheNum->flag; Num->lsign = CacheNum->lsign; Num->pre = CacheNum->pre; - Num->pos = CacheNum->pos; + 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; @@ -2210,213 +2341,332 @@ NUM_prepare_locale(NUMProc *Np) } /* ---------- - * SET SIGN macro - set 'S' or 'PR' befor number + * Return pointer of last relevant number after decimal point + * 12.0500 --> last relevant is '5' * ---------- - */ -#define SET_SIGN(_np) { \ - if ((_np)->sign_wrote==0) { \ - if (IS_BRACKET((_np)->Num)) { \ - \ - *(_np)->inout_p = '<'; \ - ++(_np)->inout_p; \ - (_np)->sign_wrote = 1; \ - \ - } else if ((_np)->Num->lsign==NUM_LSIGN_PRE && (! IS_BRACKET((_np)->Num)) && \ - (! IS_MINUS((_np)->Num)) && (! IS_PLUS((_np)->Num))) { \ - \ - if ((_np)->sign=='-') \ - strcpy((_np)->inout_p, (_np)->L_negative_sign); \ - else \ - strcpy((_np)->inout_p, (_np)->L_positive_sign); \ - (_np)->inout_p += strlen((_np)->inout_p); \ - (_np)->sign_wrote = 1; \ - \ - } else { \ - if ((_np)->sign=='-' && (_np)->Num->lsign==NUM_LSIGN_NONE \ - && (! IS_BRACKET((_np)->Num)) && \ - (! IS_MINUS((_np)->Num)) && (! IS_PLUS((_np)->Num))) { \ - \ - *(_np)->inout_p = '-'; \ - ++(_np)->inout_p; \ - (_np)->sign_wrote=1; \ - \ - } else if ((! IS_FILLMODE((_np)->Num)) && (_np)->Num->lsign==NUM_LSIGN_NONE && \ - (! IS_BRACKET((_np)->Num)) && (! IS_MINUS((_np)->Num)) && (! IS_PLUS((_np)->Num))) { \ - \ - *(_np)->inout_p = ' '; \ - ++(_np)->inout_p; \ - (_np)->sign_wrote=1; \ - } \ - } \ - } \ + */ +static char * +get_last_relevant_decnum(char *num) +{ + char *result, + *p = strchr(num, '.'); + + elog(NOTICE, "CALL: get_last_relevant_decnum()"); + + if (!p) + p = num; + result = p; + + while(*(++p)) { + if (*p!='0') + result = p; + } + + return result; } /* ---------- - * Create number - * return FALSE if any work over current NUM_[0|9|D|DEC] must be skip - * in NUM_processor() + * Number extraction for TO_NUMBER() * ---------- */ -static int -NUM_numpart(NUMProc *Np, int id) -{ - if (IS_ROMAN(Np->Num)) - return FALSE; - - /* Note: in this elog() output not set '\0' in inout - elog(DEBUG_elog_output, "sign_w: %d, count: %d, plen %d, sn: %s, inout: '%s'", - Np->sign_wrote, Np->count_num, Np->pre_number, Np->number_p, Np->inout); - */ +static void +NUM_numpart_from_char(NUMProc *Np, int id) +{ + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, " --- scan start --- "); +#endif + + if (*Np->inout_p == ' ') + Np->inout_p++; /* ---------- - * Number extraction for TO_NUMBER() + * read sign * ---------- */ - if (Np->type == FROM_CHAR) { - if (id == NUM_9 || id == NUM_0) { - if (!*(Np->number+1)) { - if (*Np->inout_p == '-' || - (IS_BRACKET(Np->Num) && - *Np->inout_p == '<' )) { - - *Np->number = '-'; - Np->inout_p++; - - } else if (*Np->inout_p == '+') { - - *Np->number = '+'; - Np->inout_p++; - - } else if (*Np->inout_p == ' ' && (! IS_FILLMODE(Np->Num))) { - Np->inout_p++; - } + if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9 || NUM_S)) { + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Try read sign (%c).", *Np->inout_p); +#endif + /* ---------- + * locale sign + * ---------- + */ + if (IS_LSIGN(Np->Num)) { + + int x = strlen(Np->L_negative_sign); + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Try read locale sign (%c).", *Np->inout_p); +#endif + if (!strncmp(Np->inout_p, Np->L_negative_sign, x)) { + Np->inout_p += x-1; + *Np->number = '-'; + return; } - if (isdigit((unsigned char) *Np->inout_p)) { - *Np->number_p = *Np->inout_p; - Np->number_p++; - } - } else { - if (id == NUM_DEC) { - *Np->number_p = '.'; - Np->number_p++; - - } else if (id == NUM_D) { - - int x = strlen(Np->decimal); - - if (!strncmp(Np->inout_p, Np->decimal, x)) { - Np->inout_p += x-1; - *Np->number_p = '.'; - Np->number_p++; - } + + x = strlen(Np->L_positive_sign); + if (!strncmp(Np->inout_p, Np->L_positive_sign, x)) { + Np->inout_p += x-1; + *Np->number = '+'; + return; } - } - return TRUE; - } + } - /* ---------- - * Add blank space (pre number) - * ---------- - */ - if ((! IS_ZERO(Np->Num)) && (! IS_FILLMODE(Np->Num)) && Np->pre_number > 0) { - *Np->inout_p = ' '; - --Np->pre_number; - --Np->count_num; - return TRUE; - } +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Try read sipmle sign (%c).", *Np->inout_p); +#endif + /* ---------- + * simple + - < > + * ---------- + */ + if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) && + *Np->inout_p == '<' )) { + + *Np->number = '-'; /* set - */ + Np->inout_p++; + + } else if (*Np->inout_p == '+') { + + *Np->number = '+'; /* set + */ + Np->inout_p++; + } + } /* ---------- - * Add zero (pre number) + * read digit * ---------- */ - if (IS_ZERO(Np->Num) && Np->pre_number > 0) { - - SET_SIGN(Np); - *Np->inout_p='0'; - --Np->pre_number; - --Np->count_num; - return TRUE; - } + if (isdigit((unsigned char) *Np->inout_p)) { + + if (Np->read_dec && Np->read_post == Np->Num->post) + return; + + *Np->number_p = *Np->inout_p; + Np->number_p++; - if (IS_FILLMODE(Np->Num) && Np->pre_number > 0) { - --Np->pre_number; - return FALSE; - } + if (Np->read_dec) + Np->read_post++; + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Read digit (%c).", *Np->inout_p); +#endif /* ---------- - * Add sign or '<' or ' ' + * read decimal point * ---------- */ - if (Np->number_p==Np->number && Np->sign_wrote==0) { - SET_SIGN(Np); + } else if (IS_DECIMAL(Np->Num)) { + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Try read decimal point (%c).", *Np->inout_p); +#endif + if (*Np->inout_p == '.') { + + *Np->number_p = '.'; + Np->number_p++; + Np->read_dec = TRUE; + + } else { + + int x = strlen(Np->decimal); + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Try read locale point (%c).", *Np->inout_p); +#endif + if (!strncmp(Np->inout_p, Np->decimal, x)) { + Np->inout_p += x-1; + *Np->number_p = '.'; + Np->number_p++; + Np->read_dec = TRUE; + } + } } +} + +/* ---------- + * Add digit or sign to number-string + * ---------- + */ +static void +NUM_numpart_to_char(NUMProc *Np, int id) +{ + if (IS_ROMAN(Np->Num)) + return; + + /* Note: in this elog() output not set '\0' in 'inout' */ + +#ifdef DEBUG_TO_FROM_CHAR + /* + * Np->num_curr is number of current item in format-picture, it is not + * current position in inout! + */ + elog(DEBUG_elog_output, + + "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: '%s', INOUT: '%s'", + Np->sign_wrote, + Np->num_curr, + Np->number_p, + Np->inout); +#endif + Np->num_in = FALSE; /* ---------- - * Add decimal point + * Write sign * ---------- */ - if (*Np->number_p=='.') { - strcpy(Np->inout_p, Np->decimal); - Np->inout_p += strlen(Np->inout_p); - if (*Np->number_p) - ++Np->number_p; - return FALSE; - } - - if (*Np->number_p) { - - /* ---------- - * Copy number string to inout string - * ---------- - */ - *Np->inout_p = *Np->number_p; - ++Np->number_p; + if (Np->num_curr == Np->sign_pos && Np->sign_wrote==FALSE) { + +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing sign to position: %d", Np->num_curr); +#endif + if (IS_LSIGN(Np->Num)) { - Np->in_number = 1; + /* ---------- + * Write locale SIGN + * ---------- + */ + if (Np->sign=='-') + strcpy(Np->inout_p, Np->L_negative_sign); + else + strcpy(Np->inout_p, Np->L_positive_sign); + Np->inout_p += strlen(Np->inout_p); + + } else if (IS_BRACKET(Np->Num)) { + *Np->inout_p = '<'; /* Write < */ + ++Np->inout_p; + } else if (Np->sign=='+') { + *Np->inout_p = ' '; /* Write + */ + ++Np->inout_p; + + } else if (Np->sign=='-') { /* Write - */ + *Np->inout_p = '-'; + ++Np->inout_p; + } + Np->sign_wrote = TRUE; + + } else if (Np->sign_wrote && IS_BRACKET(Np->Num) && + (Np->num_curr == Np->num_count + (Np->num_pre ? 1 : 0) + + (IS_DECIMAL(Np->Num) ? 1 : 0))) { /* ---------- - * Number end (set post 'S' or '>' + * Write close BRACKET * ---------- - */ - if ((--Np->count_num)==0) { - - if (IS_BRACKET(Np->Num)) { + */ +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing bracket to position %d", Np->num_curr); +#endif + *Np->inout_p = '>'; /* Write '>' */ + ++Np->inout_p; + } + + /* ---------- + * digits / FM / Zero / Dec. point + * ---------- + */ + if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC || + (id == NUM_S && Np->num_curr < Np->num_pre)) { + + if (Np->num_curr < Np->num_pre && + (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num))) { + + /* ---------- + * Write blank space + * ---------- + */ + if (!IS_FILLMODE(Np->Num)) { + #ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing blank space to position %d", Np->num_curr); + #endif + *Np->inout_p = ' '; /* Write ' ' */ ++Np->inout_p; - *Np->inout_p = '>'; - Np->sign_wrote =1; } + + } else if (IS_ZERO(Np->Num) && + Np->num_curr < Np->num_pre && + Np->Num->zero_start <= Np->num_curr) { - if (Np->Num->lsign==NUM_LSIGN_POST && Np->sign_wrote==0) { - ++Np->inout_p; - if (Np->sign=='-') - strcpy(Np->inout_p, Np->L_negative_sign); - else - strcpy(Np->inout_p, Np->L_positive_sign); - Np->inout_p += strlen(Np->inout_p)-1; - Np->sign_wrote = 1; + /* ---------- + * Write ZERO + * ---------- + */ +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing zero to position %d", Np->num_curr); +#endif + *Np->inout_p = '0'; /* Write '0' */ + ++Np->inout_p; + Np->num_in = TRUE; + + } else { + + /* ---------- + * Write Decinal point + * ---------- + */ + if (*Np->number_p=='.') { + + if (!Np->last_relevant || *Np->last_relevant!='.' ) { +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing decimal point to position %d", Np->num_curr); +#endif + strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ + Np->inout_p += strlen(Np->inout_p); + + /* terrible Ora + * '0' -- 9.9 --> '0.' + */ + } else if (IS_FILLMODE(Np->Num) && *Np->number == '0' && + Np->last_relevant && *Np->last_relevant=='.' ) { + + strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ + Np->inout_p += strlen(Np->inout_p); + } + + } else { + + /* ---------- + * Write Digits + * ---------- + */ + if (Np->last_relevant && Np->number_p > Np->last_relevant && + id != NUM_0) + ; + + /* terrible Ora format: + * '0.1' -- 9.9 --> ' .1' + */ + else if (!IS_ZERO(Np->Num) && *Np->number == '0' && + Np->number == Np->number_p && Np->Num->post !=0) { + + if (!IS_FILLMODE(Np->Num)) { + *Np->inout_p = ' '; + ++Np->inout_p; + + /* total terible Ora: + * '0' -- FM9.9 --> '0.' + */ + } else if (Np->last_relevant && *Np->last_relevant=='.') { + *Np->inout_p = '0'; + ++Np->inout_p; + } + + } else { +#ifdef DEBUG_TO_FROM_CHAR + elog(DEBUG_elog_output, "Writing digit '%c' to position %d", *Np->number_p, Np->num_curr); +#endif + *Np->inout_p = *Np->number_p; /* Write DIGIT */ + ++Np->inout_p; + Np->num_in = TRUE; + } } - } - } else - return FALSE; - return TRUE; + ++Np->number_p; + } + } + + ++Np->num_curr; } -/* ---------- - * Master function for NUMBER version. - * type (variant): - * TO_CHAR - * -> create formatted string by course of FormatNode - * - * FROM_CHAR (TO_NUMBER) - * -> extract number string from formatted string (reverse TO_CHAR) - * - * - ! this version use non-string 'inout' VARDATA(), - * and 'plen' is used for VARSIZE() - * - value 'sign' is not used - * - number is creating in Np->number and first position (*Np->number) - * in this buffer is reserved for +/- sign - * ---------- - */ static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int plen, int sign, int type) @@ -2427,32 +2677,24 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, Np->Num = Num; Np->type = type; Np->number = number; - - if (type == TO_CHAR) { - Np->pre_number = plen; - Np->sign = sign; - - } else if (type == FROM_CHAR) { - Np->pre_number = 0; - *Np->number = ' '; /* sign space */ - *(Np->number+1) = '\0'; - Np->sign = 0; - } - Np->inout = inout; - - Np->sign_wrote = Np->count_num = Np->in_number = 0; - + Np->last_relevant = NULL; + Np->read_post = 0; + Np->read_dec = FALSE; + + if (Np->Num->zero_start) + --Np->Num->zero_start; + /* ---------- - * Roman corection + * Roman correction * ---------- */ if (IS_ROMAN(Np->Num)) { if (Np->type==FROM_CHAR) - elog(ERROR, "to_number: RN is not supported"); + elog(ERROR, "to_number(): RN is not supported"); - Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->pos = - Np->Num->pre = Np->pre_number = Np->sign = 0; + Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post = + Np->Num->pre = Np->num_pre = Np->sign = 0; if (IS_FILLMODE(Np->Num)){ Np->Num->flag = 0; @@ -2462,37 +2704,128 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, } Np->Num->flag |= NUM_F_ROMAN; } - - /* ---------- - * Check Num struct + + /* ---------- + * Sign * ---------- */ - if (Np->sign=='+') - Np->Num->flag &= ~NUM_F_BRACKET; + if (type == FROM_CHAR) { + Np->sign = FALSE; + Np->sign_pos = -1; + } else { + Np->sign = sign; + + if (Np->sign != '-') { + Np->Num->flag &= ~NUM_F_BRACKET; + Np->Num->flag &= ~NUM_F_MINUS; + } else if (Np->sign != '+') { + Np->Num->flag &= ~NUM_F_PLUS; + } - if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num) - Np->Num->lsign = NUM_LSIGN_POST; + if (Np->sign=='+' && IS_FILLMODE(Np->Num) && !IS_LSIGN(Np->Num)) + Np->sign_wrote = TRUE; /* needn't sign */ + else + Np->sign_wrote = FALSE; /* need sign */ - /* set counter (number of all digits) */ - Np->count_num = Np->Num->pos + Np->Num->pre; + Np->sign_pos = -1; - if (Np->type==TO_CHAR && IS_FILLMODE(Np->Num) && (! IS_ZERO(Np->Num))) - Np->count_num -= Np->pre_number; + if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num) + Np->Num->lsign = NUM_LSIGN_POST; + + /* MI/PL/SG - write sign itself and not in number */ + if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)) + Np->sign_wrote = TRUE; /* needn't sign */ + } + + /* ---------- + * Count + * ---------- + */ + Np->num_count = Np->Num->post + Np->Num->pre -1; + + if (type == TO_CHAR) { + Np->num_pre = plen; + + if (IS_FILLMODE(Np->Num)) { + if (IS_DECIMAL(Np->Num)) + Np->last_relevant = get_last_relevant_decnum( + Np->number + + ((Np->Num->zero_end - Np->num_pre > 0) ? + Np->Num->zero_end - Np->num_pre : 0)); + } + + if (!Np->sign_wrote && Np->num_pre==0) + ++Np->num_count; + + if (!Np->sign_wrote) { + + /* ---------- + * Set SING position + * ---------- + */ + if (Np->Num->lsign == NUM_LSIGN_POST) { + Np->sign_pos = Np->num_count + (Np->num_pre ? 1 : 0); + + if (IS_DECIMAL(Np->Num)) /* decimal point correctio */ + ++Np->sign_pos; + } + else if (IS_ZERO(Np->Num) && Np->num_pre > Np->Num->zero_start) + Np->sign_pos = Np->Num->zero_start ? Np->Num->zero_start : 0; + + else + Np->sign_pos = Np->num_pre && !IS_FILLMODE(Np->Num) ? Np->num_pre : 0; + + /* ---------- + * terrible Ora format + * ---------- + */ + if (!IS_ZERO(Np->Num) && *Np->number == '0' && + !IS_FILLMODE(Np->Num) && Np->Num->post!=0) { + + ++Np->sign_pos; + + if (IS_LSIGN(Np->Num)) { + if (Np->Num->lsign == NUM_LSIGN_PRE) + ++Np->sign_pos; + else + --Np->sign_pos; + } + } + } + + } else { + Np->num_pre = 0; + *Np->number = ' '; /* sign space */ + *(Np->number+1) = '\0'; + } + + Np->num_in = 0; + Np->num_curr = 0; #ifdef DEBUG_TO_FROM_CHAR - elog(DEBUG_elog_output, "NUM: '%s', PRE: %d, POS: %d, PLEN: %d, LSIGN: %d, DECIMAL: %d, MULTI: %d", - Np->number, Np->Num->pre, Np->Num->pos, - Np->pre_number, Np->Num->lsign,IS_DECIMAL(Np->Num), - Np->Num->multi); + elog(DEBUG_elog_output, + + "\n\tNUM: '%s'\n\tPRE: %d\n\tPOST: %d\n\tNUM_COUNT: %d\n\tNUM_PRE: %d\n\tSIGN_POS: %d\n\tSIGN_WROTE: %s\n\tZERO: %s\n\tZERO_START: %d\n\tZERO_END: %d\n\tLAST_RELEVANT: %s", + Np->number, + Np->Num->pre, + Np->Num->post, + Np->num_count, + Np->num_pre, + Np->sign_pos, + Np->sign_wrote ? "Yes" : "No", + IS_ZERO(Np->Num) ? "Yes" : "No", + Np->Num->zero_start, + Np->Num->zero_end, + Np->last_relevant ? Np->last_relevant : "" + ); #endif + /* ---------- * Locale * ---------- */ NUM_prepare_locale(Np); - /* need for DEBUG: memset(Np->inout, '\0', Np->count_num );*/ - /* ---------- * Processor direct cycle * ---------- @@ -2501,7 +2834,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, Np->number_p=Np->number+1; /* first char is space for sign */ else if (Np->type == TO_CHAR) Np->number_p=Np->number; - + for(n=node, Np->inout_p=Np->inout; n->type != NODE_TYPE_END; n++) { if (Np->type == FROM_CHAR) { @@ -2529,15 +2862,19 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, case NUM_0: case NUM_DEC: case NUM_D: - - if (NUM_numpart(Np, n->key->id)) - break; - else - continue; + case NUM_S: + case NUM_PR: + if (Np->type == TO_CHAR) { + NUM_numpart_to_char(Np, n->key->id); + continue; /* for() */ + } else { + NUM_numpart_from_char(Np, n->key->id); + break; /* switch() case: */ + } case NUM_COMMA: if (Np->type == TO_CHAR) { - if (!Np->in_number) { + if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; else @@ -2546,7 +2883,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, *Np->inout_p = ','; } else if (Np->type == FROM_CHAR) { - if (!Np->in_number) { + if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; } @@ -2555,7 +2892,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, case NUM_G: if (Np->type == TO_CHAR) { - if (!Np->in_number) { + if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; else { @@ -2569,7 +2906,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, } } else if (Np->type == FROM_CHAR) { - if (!Np->in_number) { + if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; } @@ -2587,69 +2924,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, } break; - case NUM_MI: - if (Np->sign_wrote==1 || IS_BRACKET(Np->Num)) { - if (Np->type == TO_CHAR) - continue; - else - break; - } - if (Np->type == TO_CHAR) { - if (Np->sign=='-') - *Np->inout_p = '-'; - else - *Np->inout_p = ' '; - - } else if (Np->type == FROM_CHAR) { - if (*Np->inout_p == '-') - *Np->number = '-'; - } - Np->sign_wrote=1; - break; - - case NUM_PL: - if (Np->sign_wrote==1 || IS_BRACKET(Np->Num)) { - if (Np->type == TO_CHAR) - continue; - else - break; - } - if (Np->type == TO_CHAR) { - if (Np->sign=='+') - *Np->inout_p = '+'; - else - *Np->inout_p = ' '; - - } else if (Np->type == FROM_CHAR) { - if (*Np->inout_p == '+') - *Np->number = '+'; - } - Np->sign_wrote=1; - break; - - case NUM_SG: - if (Np->sign_wrote==1 || IS_BRACKET(Np->Num)) { - if (Np->type == TO_CHAR) - continue; - else - break; - } - if (Np->type == TO_CHAR) - *Np->inout_p = Np->sign; - - else if (Np->type == FROM_CHAR) { - if (*Np->inout_p == '-') - *Np->number = '-'; - else if (*Np->inout_p == '+') - *Np->number = '+'; - } - Np->sign_wrote=1; - break; - case NUM_RN: - if (Np->type == FROM_CHAR) - elog(ERROR, "TO_NUMBER: internal error #1"); - if (IS_FILLMODE(Np->Num)) { strcpy(Np->inout_p, Np->number_p); Np->inout_p += strlen(Np->inout_p) - 1; @@ -2658,9 +2933,6 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, break; case NUM_rn: - if (Np->type == FROM_CHAR) - elog(ERROR, "TO_NUMBER: internal error #2"); - if (IS_FILLMODE(Np->Num)) { strcpy(Np->inout_p, str_tolower(Np->number_p)); Np->inout_p += strlen(Np->inout_p) - 1; @@ -2688,29 +2960,45 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, Np->inout_p += 1; break; - case NUM_S: - /* ---------- - * 'S' for TO_CHAR is in NUM_numpart() - * ---------- - */ - if (Np->type == FROM_CHAR && Np->sign_wrote==FALSE) { - - int x = strlen(Np->L_negative_sign); - if (!strncmp(Np->inout_p, Np->L_negative_sign, x)) { - Np->inout_p += x-1; + case NUM_MI: + if (Np->type == TO_CHAR) { + if (Np->sign=='-') + *Np->inout_p = '-'; + else + *Np->inout_p = ' '; + + } else if (Np->type == FROM_CHAR) { + if (*Np->inout_p == '-') *Np->number = '-'; - break; - } - - x = strlen(Np->L_positive_sign); - if (!strncmp(Np->inout_p, Np->L_positive_sign, x)) { - Np->inout_p += x-1; - *Np->number = '+'; - break; - } - } else - continue; + } break; + + case NUM_PL: + if (Np->type == TO_CHAR) { + if (Np->sign=='+') + *Np->inout_p = '+'; + else + *Np->inout_p = ' '; + + } else if (Np->type == FROM_CHAR) { + if (*Np->inout_p == '+') + *Np->number = '+'; + } + break; + + case NUM_SG: + if (Np->type == TO_CHAR) + *Np->inout_p = Np->sign; + + else if (Np->type == FROM_CHAR) { + if (*Np->inout_p == '-') + *Np->number = '-'; + else if (*Np->inout_p == '+') + *Np->number = '+'; + } + break; + + default: continue; break; @@ -2729,16 +3017,29 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, if (Np->type == TO_CHAR) { *Np->inout_p = '\0'; - return Np->inout; + return Np->inout; } else if (Np->type == FROM_CHAR) { - *Np->number_p = '\0'; + + if (*(Np->number_p-1) == '.') + *(Np->number_p-1) = '\0'; + else + *Np->number_p = '\0'; + + /* ---------- + * Correction - precision of dec. number + * ---------- + */ + Np->Num->post = Np->read_post; + #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number); #endif return Np->number; } else return NULL; + + return NULL; } /* ---------- @@ -2811,7 +3112,7 @@ numeric_to_number(text *value, text *fmt) NUM_processor(format, &Num, VARDATA(value), numstr, VARSIZE(value) - VARHDRSZ, 0, FROM_CHAR); - scale = Num.pos; + scale = Num.post; precision = MAX(0, Num.pre) + scale; return numeric_in(numstr, 0, ((precision << 16) | scale) + VARHDRSZ); @@ -2853,7 +3154,7 @@ numeric_to_char(Numeric value, text *fmt) Num.pre += Num.multi; } - orgnum = numeric_out( numeric_round(val, Num.pos) ); + orgnum = numeric_out( numeric_round(val, Num.post) ); if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum+1; @@ -2872,10 +3173,10 @@ numeric_to_char(Numeric value, text *fmt) else if (len > Num.pre) { fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; - fill_str(numstr + 1 + Num.pre, '#', Num.pos); + fill_str(numstr + 1 + Num.pre, '#', Num.post); } } - /*dump_node(format, VARSIZE(fmt) - VARHDRSZ);*/ + NUM_TOCHAR_finish; return result; } @@ -2921,16 +3222,16 @@ int4_to_char(int32 value, text *fmt) } else sign = '+'; - if (Num.pos) { + if (Num.post) { int i; - numstr = palloc( len + 1 + Num.pos ); + numstr = palloc( len + 1 + Num.post ); strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); *(numstr + len) = '.'; - for(i=len+1; i<=Num.pos+len+1; i++) + for(i=len+1; i<=Num.post+len+1; i++) *(numstr+i) = '0'; - *(numstr + Num.pos + len + 1) = '\0'; + *(numstr + Num.post + len + 1) = '\0'; pfree(orgnum); orgnum = numstr; } else @@ -2941,12 +3242,10 @@ int4_to_char(int32 value, text *fmt) else if (len > Num.pre) { fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; - fill_str(numstr + 1 + Num.pre, '#', Num.pos); + fill_str(numstr + 1 + Num.pre, '#', Num.post); } } - /*dump_node(format, len);*/ - NUM_TOCHAR_finish; return result; } @@ -2993,16 +3292,16 @@ int8_to_char(int64 *value, text *fmt) } else sign = '+'; - if (Num.pos) { + if (Num.post) { int i; - numstr = palloc( len + 1 + Num.pos ); + numstr = palloc( len + 1 + Num.post ); strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); *(numstr + len) = '.'; - for(i=len+1; i<=Num.pos+len+1; i++) + for(i=len+1; i<=Num.post+len+1; i++) *(numstr+i) = '0'; - *(numstr + Num.pos + len + 1) = '\0'; + *(numstr + Num.post + len + 1) = '\0'; pfree(orgnum); orgnum = numstr; } else @@ -3013,7 +3312,7 @@ int8_to_char(int64 *value, text *fmt) else if (len > Num.pre) { fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; - fill_str(numstr + 1 + Num.pre, '#', Num.pos); + fill_str(numstr + 1 + Num.pre, '#', Num.post); } } @@ -3058,10 +3357,10 @@ float4_to_char(float32 value, text *fmt) if (Num.pre > len) plen = Num.pre - len; if (len >= FLT_DIG) - Num.pos = 0; - else if (Num.pos + len > FLT_DIG) - Num.pos = FLT_DIG - len; - sprintf(orgnum, "%.*f", Num.pos, *val); + Num.post = 0; + else if (Num.post + len > FLT_DIG) + Num.post = FLT_DIG - len; + sprintf(orgnum, "%.*f", Num.post, *val); if (*orgnum == '-') { /* < 0 */ sign = '-'; @@ -3081,7 +3380,7 @@ float4_to_char(float32 value, text *fmt) else if (len > Num.pre) { fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; - fill_str(numstr + 1 + Num.pre, '#', Num.pos); + fill_str(numstr + 1 + Num.pre, '#', Num.post); } } @@ -3125,10 +3424,10 @@ float8_to_char(float64 value, text *fmt) if (Num.pre > len) plen = Num.pre - len; if (len >= DBL_DIG) - Num.pos = 0; - else if (Num.pos + len > DBL_DIG) - Num.pos = DBL_DIG - len; - sprintf(orgnum, "%.*f", Num.pos, *val); + Num.post = 0; + else if (Num.post + len > DBL_DIG) + Num.post = DBL_DIG - len; + sprintf(orgnum, "%.*f", Num.post, *val); if (*orgnum == '-') { /* < 0 */ sign = '-'; @@ -3148,7 +3447,7 @@ float8_to_char(float64 value, text *fmt) else if (len > Num.pre) { fill_str(numstr, '#', Num.pre); *(numstr + Num.pre) = '.'; - fill_str(numstr + 1 + Num.pre, '#', Num.pos); + fill_str(numstr + 1 + Num.pre, '#', Num.post); } } diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index 7688a753db..1711eb269a 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -1,12 +1,17 @@ -/*------ +/* ----------------------------------------------------------------------- * pg_locale.c * - * The PostgreSQL locale utils. + * $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.2 2000/02/08 15:56:55 momjian Exp $ * - * 2000 Karel Zak - Zakkr * - *------ + * Portions Copyright (c) 1999-2000, PostgreSQL, Inc + * + * The PostgreSQL locale utils. + * + * Karel Zak - Zakkr + * + * ----------------------------------------------------------------------- */ #include diff --git a/src/include/utils/formatting.h b/src/include/utils/formatting.h index b5b1a5ff1f..51c649fd9d 100644 --- a/src/include/utils/formatting.h +++ b/src/include/utils/formatting.h @@ -2,13 +2,15 @@ /* ----------------------------------------------------------------------- * formatting.h * - * $Id: formatting.h,v 1.1 2000/01/25 23:53:56 momjian Exp $ + * $Id: formatting.h,v 1.2 2000/02/08 15:56:57 momjian Exp $ * * + * Portions Copyright (c) 1999-2000, PostgreSQL, Inc + * * The PostgreSQL routines for a DateTime/int/float/numeric formatting, * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * - * 1999 Karel Zak "Zakkr" + * Karel Zak - Zakkr * * ----------------------------------------------------------------------- */ diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h index e5aee46c9b..ac940c1b55 100644 --- a/src/include/utils/pg_locale.h +++ b/src/include/utils/pg_locale.h @@ -1,14 +1,19 @@ -/*------ +/* ----------------------------------------------------------------------- * pg_locale.h * - * The PostgreSQL locale utils + * $Header: /cvsroot/pgsql/src/include/utils/pg_locale.h,v 1.2 2000/02/08 15:57:01 momjian Exp $ * - * 2000 Karel Zak - Zakkr * - *------ - */ - + * Portions Copyright (c) 1999-2000, PostgreSQL, Inc + * + * The PostgreSQL locale utils. + * + * Karel Zak - Zakkr + * + * ----------------------------------------------------------------------- + */ + #ifndef _PG_LOCALE_ #define _PG_LOCALE_