Commit 394af527 authored by Bruce Momjian's avatar Bruce Momjian

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 <zakkr@zf.jcu.cz>              http://home.zf.jcu.cz/~zakkr/
parent 9ceb5d8a
...@@ -518,7 +518,7 @@ ...@@ -518,7 +518,7 @@
<para> <para>
<table tocentry="1"> <table tocentry="1">
<title>Format-pictures for datetime to_char() version.</title> <title>Format-pictures for date/time to_char() version.</title>
<tgroup cols="2"> <tgroup cols="2">
<thead> <thead>
<row> <row>
...@@ -662,12 +662,12 @@ ...@@ -662,12 +662,12 @@
<para> <para>
All format-pictures allow use suffixes (postfix / prefix). The suffix is 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.
</para> </para>
<para> <para>
<table tocentry="1"> <table tocentry="1">
<title>Suffixes for format-pictures for datetime to_char() version.</title> <title>Suffixes for format-pictures for date/time to_char() version.</title>
<tgroup cols="3"> <tgroup cols="3">
<thead> <thead>
<row> <row>
...@@ -695,7 +695,7 @@ ...@@ -695,7 +695,7 @@
<row> <row>
<entry> FX </entry> <entry> FX </entry>
<entry> FX - (Fixed format) global format-picture switch. <entry> 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. </entry> not use. Must by used as first item in formt-picture. </entry>
<entry> FX Month DD Day </entry> <entry> FX Month DD Day </entry>
</row> </row>
...@@ -714,7 +714,7 @@ ...@@ -714,7 +714,7 @@
</para> </para>
<para> <para>
'"' - string between a quotation marks is skipen and not is parsed. '"' - 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\\"'.
</para> </para>
<para> <para>
text - the PostgreSQL's to_char() support text without '"', but string text - the PostgreSQL's to_char() support text without '"', but string
...@@ -776,7 +776,11 @@ ...@@ -776,7 +776,11 @@
</row> </row>
<row> <row>
<entry> PL </entry> <entry> PL </entry>
<entry> return plus sign on specified position (if number > 0) </entry> <entry> return plus sign on specified position (if number > 0) - PostgreSQL extension </entry>
</row>
<row>
<entry> SG </entry>
<entry> return plus/minus sign on specified position - PostgreSQL extension </entry>
</row> </row>
<row> <row>
<entry> RN </entry> <entry> RN </entry>
...@@ -784,7 +788,7 @@ ...@@ -784,7 +788,7 @@
</row> </row>
<row> <row>
<entry> TH or th </entry> <entry> TH or th </entry>
<entry> convert number to ordinal number (not convert numbers under zero and decimal numbers) </entry> <entry> convert number to ordinal number (not convert numbers under zero and decimal numbers) - PostgreSQL extension </entry>
</row> </row>
<row> <row>
<entry> V </entry> <entry> V </entry>
...@@ -801,9 +805,12 @@ ...@@ -801,9 +805,12 @@
</para> </para>
<para> <para>
The PostgreSQL to_char() not support absurd to_char(0.1, '99.99') Note: A sign formatted via 'SG', 'PL' or 'MI' is not anchor in number;
--> <ProgramListing> ' .10' </ProgramListing> format. to_char(-12, 'S9999') produce: <ProgramListing> ' -12' </ProgramListing>,
</para> but to_char(-12, 'MI9999') produce: <ProgramListing> '- 12' </ProgramListing>.
The Oracle not allow use 'MI' ahead of '9', in the Oracle must be it always
after '9'.
</para>
<para> <para>
<table tocentry="1"> <table tocentry="1">
...@@ -825,16 +832,24 @@ ...@@ -825,16 +832,24 @@
<entry><ProgramListing> 'Tuesday, 05:39:18' </ProgramListing></entry> <entry><ProgramListing> 'Tuesday, 05:39:18' </ProgramListing></entry>
</row> </row>
<row> <row>
<entry> to_char( 0.1, '99.99') </entry> <entry> to_char( -0.1, '99.99') </entry>
<entry><ProgramListing> ' 0.10' </ProgramListing></entry> <entry><ProgramListing> ' -.10' </ProgramListing></entry>
</row>
<row>
<entry> to_char( -0.1, 'FM9.99') </entry>
<entry><ProgramListing> '-.1' </ProgramListing></entry>
</row> </row>
<row> <row>
<entry> to_char( 0.1, '0.9') </entry> <entry> to_char( 0.1, '0.9') </entry>
<entry><ProgramListing> ' 0.1' </ProgramListing></entry> <entry><ProgramListing> ' 0.1' </ProgramListing></entry>
</row> </row>
<row> <row>
<entry> to_char( 0.1, '090.9') </entry> <entry> to_char( 12, '9990999.9') </entry>
<entry><ProgramListing> ' 000.1' </ProgramListing></entry> <entry><ProgramListing> ' 0012.0' </ProgramListing></entry>
</row>
<row>
<entry> to_char( 12, 'FM9990999.9') </entry>
<entry><ProgramListing> '0012' </ProgramListing></entry>
</row> </row>
<row> <row>
<entry> to_char( 485, '999') </entry> <entry> to_char( 485, '999') </entry>
...@@ -844,18 +859,6 @@ ...@@ -844,18 +859,6 @@
<entry> to_char( -485, '999') </entry> <entry> to_char( -485, '999') </entry>
<entry><ProgramListing> '-485' </ProgramListing></entry> <entry><ProgramListing> '-485' </ProgramListing></entry>
</row> </row>
<row>
<entry> to_char( 485, '09999') </entry>
<entry><ProgramListing> ' 00485' </ProgramListing></entry>
</row>
<row>
<entry> to_char( 485, 'FM09999') </entry>
<entry><ProgramListing> '00485' </ProgramListing></entry>
</row>
<row>
<entry> to_char( 485, 'FM999') </entry>
<entry><ProgramListing> '485' </ProgramListing></entry>
</row>
<row> <row>
<entry> to_char( 485, '9 9 9') </entry> <entry> to_char( 485, '9 9 9') </entry>
<entry><ProgramListing> ' 4 8 5' </ProgramListing></entry> <entry><ProgramListing> ' 4 8 5' </ProgramListing></entry>
......
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.c * 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(); * TO_CHAR(); TO_DATETIME(); TO_DATE(); TO_NUMBER();
* *
* The PostgreSQL routines for a DateTime/int/float/numeric formatting, * The PostgreSQL routines for a DateTime/int/float/numeric formatting,
* inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
* *
* 1999 Karel Zak "Zakkr"
*
* *
* Cache & Memory: * Cache & Memory:
* Routines use (itself) internal cache for format pictures. If * Routines use (itself) internal cache for format pictures. If
...@@ -33,13 +35,16 @@ ...@@ -33,13 +35,16 @@
* *
* Supported types for to_char(): * Supported types for to_char():
* *
* DateTime, Numeric, int4, int8, float4, float8 * Timestamp, DateTime, Numeric, int4, int8, float4, float8
* *
* Supported types for reverse conversion: * Supported types for reverse conversion:
* *
* Datetime - to_datetime() * Datetime - to_datetime()
* Date - to_date() * Date - to_date()
* Numeric - to_number() * Numeric - to_number()
*
*
* Karel Zak - Zakkr
* *
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
*/ */
...@@ -106,8 +111,8 @@ ...@@ -106,8 +111,8 @@
* External (defined in PgSQL dt.c (datetime utils)) * External (defined in PgSQL dt.c (datetime utils))
* ---------- * ----------
*/ */
extern char *months[], /* month abbreviation */ extern char *months[], /* month abbreviation */
*days[]; /* full days */ *days[]; /* full days */
/* ---------- /* ----------
* Format parser structs * Format parser structs
...@@ -231,11 +236,13 @@ static int DCH_global_flag = 0; ...@@ -231,11 +236,13 @@ static int DCH_global_flag = 0;
*/ */
typedef struct { typedef struct {
int pre, /* (count) numbers before decimal */ int pre, /* (count) numbers before decimal */
pos, /* (count) numbers after decimal */ post, /* (count) numbers after decimal */
lsign, /* want locales sign */ lsign, /* want locales sign */
flag, /* number parametrs */ flag, /* number parametrs */
pre_lsign_num, /* tmp value for lsign */ pre_lsign_num, /* tmp value for lsign */
multi, /* multiplier for 'V' */ multi, /* multiplier for 'V' */
zero_start, /* position of first zero */
zero_end, /* position of last zero */
need_locale; /* needs it locale */ need_locale; /* needs it locale */
} NUMDesc; } NUMDesc;
...@@ -270,6 +277,7 @@ typedef struct { ...@@ -270,6 +277,7 @@ typedef struct {
#define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE) #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
#define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET) #define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET)
#define IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS) #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_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
#define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN) #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN)
#define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI) #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI)
...@@ -350,12 +358,13 @@ static KeySuffix DCH_suff[] = { ...@@ -350,12 +358,13 @@ static KeySuffix DCH_suff[] = {
* Position for the keyword is simular as position in the enum DCH/NUM_poz * 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 * For fast search is used the 'int index[]', index is ascii table from position
* skiped), in this index is DCH_ enums for each ASCII position or -1 if * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII
* char is not used in the KeyWord. Search example for string "MM": * position or -1 if char is not used in the KeyWord. Search example for
* 1) see in index to index[77-32] (77 = 'M'), * string "MM":
* 2) take keywords position from index[77-32] * 1) see in index to index['M' - 32],
* 3) run sequential search in keywords[] from position * 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] = { ...@@ -512,7 +521,7 @@ static int DCH_index[256 - 32] = {
/* /*
0 1 2 3 4 5 6 7 8 9 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, -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 ...@@ -562,18 +571,24 @@ typedef struct NUMProc
{ {
int type; /* FROM_CHAR (TO_NUMBER) or TO_CHAR */ 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 '+' */ read_dec, /* to_number - was read dec. point */
sign_wrote, /* is sign wrote */ read_post; /* to_number - number of dec. digit */
count_num, /* number of non-write digits */
in_number, /* is inside number */
pre_number; /* space before number */
char *number, /* string with number */ char *number, /* string with number */
*number_p, /* pointer to current number pozition */ *number_p, /* pointer to current number pozition */
*inout, /* in / out buffer */ *inout, /* in / out buffer */
*inout_p, /* pointer to current inout pozition */ *inout_p, /* pointer to current inout pozition */
*last_relevant, /* last relevant number after decimal point */
*L_negative_sign, /* Locale */ *L_negative_sign, /* Locale */
*L_positive_sign, *L_positive_sign,
...@@ -592,7 +607,7 @@ static KeySuffix *suff_search(char *str, KeySuffix *suf, int type); ...@@ -592,7 +607,7 @@ static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
static void NUMDesc_prepare(NUMDesc *num, FormatNode *n); static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
static void parse_format(FormatNode *node, char *str, KeyWord *kw, static void parse_format(FormatNode *node, char *str, KeyWord *kw,
KeySuffix *suf, int *index, int ver, NUMDesc *Num); 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 #ifdef DEBUG_TO_FROM_CHAR
static void dump_index(KeyWord *k, int *index); static void dump_index(KeyWord *k, int *index);
...@@ -614,7 +629,9 @@ static FormatNode *NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, ...@@ -614,7 +629,9 @@ static FormatNode *NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat,
NUMDesc *CacheNum, NUMDesc *Num, char *pars_str, int *flag); NUMDesc *CacheNum, NUMDesc *Num, char *pars_str, int *flag);
static char *int_to_roman(int number); static char *int_to_roman(int number);
static void NUM_prepare_locale(NUMProc *Np); 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, static char *NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
int plen, int sign, int type); int plen, int sign, int type);
...@@ -677,27 +694,37 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) ...@@ -677,27 +694,37 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
switch(n->key->id) { switch(n->key->id) {
case NUM_9: case NUM_9:
if (IS_BRACKET(num))
elog(ERROR, "to_char/to_number(): '9' must be ahead of 'PR'.");
if (IS_MULTI(num)) { if (IS_MULTI(num)) {
++num->multi; ++num->multi;
break; break;
} }
if (IS_DECIMAL(num)) if (IS_DECIMAL(num))
++num->pos; ++num->post;
else else
++num->pre; ++num->pre;
break; break;
case NUM_0: 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->flag |= NUM_F_ZERO;
num->zero_start = num->pre + 1;
}
if (! IS_DECIMAL(num)) if (! IS_DECIMAL(num))
++num->pre; ++num->pre;
else else
++num->pos; ++num->post;
num->zero_end = num->pre + num->post;
break; break;
case NUM_B: 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; num->flag |= NUM_F_BLANK;
break; break;
...@@ -706,9 +733,9 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) ...@@ -706,9 +733,9 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
num->need_locale = TRUE; num->need_locale = TRUE;
case NUM_DEC: case NUM_DEC:
if (IS_DECIMAL(num)) 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)) 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; num->flag |= NUM_F_DECIMAL;
break; break;
...@@ -717,33 +744,53 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) ...@@ -717,33 +744,53 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
break; break;
case NUM_S: 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)) { if (! IS_DECIMAL(num)) {
num->lsign = NUM_LSIGN_PRE; num->lsign = NUM_LSIGN_PRE;
num->pre_lsign_num = num->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) { } else if (num->lsign == NUM_LSIGN_NONE) {
num->lsign = NUM_LSIGN_POST; num->lsign = NUM_LSIGN_POST;
num->need_locale = TRUE; num->need_locale = TRUE;
num->flag |= NUM_F_LSIGN;
} }
break; break;
case NUM_MI: 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; num->flag |= NUM_F_MINUS;
break; break;
case NUM_PL: 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; num->flag |= NUM_F_PLUS;
break; break;
case NUM_SG: 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_MINUS;
num->flag |= NUM_F_PLUS; num->flag |= NUM_F_PLUS;
break; break;
case NUM_PR: 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; num->flag |= NUM_F_BRACKET;
break; break;
case NUM_rn: case NUM_rn:
case NUM_RN: case NUM_RN:
num->flag |= NUM_F_ROMAN; num->flag |= NUM_F_ROMAN;
...@@ -756,9 +803,12 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) ...@@ -756,9 +803,12 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n)
case NUM_V: case NUM_V:
if (IS_DECIMAL(num)) 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; num->flag |= NUM_F_MULTI;
break; break;
case NUM_E:
elog(ERROR, "to_char/to_number(): 'E' is not supported.");
} }
return; return;
...@@ -782,7 +832,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw, ...@@ -782,7 +832,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
last=0; last=0;
#ifdef DEBUG_TO_FROM_CHAR #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, "to-from_char(): run parser."); elog(DEBUG_elog_output, "to_char/number(): run parser.");
#endif #endif
n = node; n = node;
...@@ -895,7 +945,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw, ...@@ -895,7 +945,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
* ---------- * ----------
*/ */
static char * static char *
DCH_action(FormatNode *node, char *inout, int flag) DCH_processor(FormatNode *node, char *inout, int flag)
{ {
FormatNode *n; FormatNode *n;
char *s; char *s;
...@@ -919,7 +969,7 @@ DCH_action(FormatNode *node, char *inout, int flag) ...@@ -919,7 +969,7 @@ DCH_action(FormatNode *node, char *inout, int flag)
len = n->key->action(n->key->id, s, n->suffix, flag, n); len = n->key->action(n->key->id, s, n->suffix, flag, n);
if (len > 0) if (len > 0)
s += len; s += len;
else else if (len == -1)
continue; continue;
} else { } else {
...@@ -972,8 +1022,8 @@ dump_node(FormatNode *node, int max) ...@@ -972,8 +1022,8 @@ dump_node(FormatNode *node, int max)
for(a=0, n=node; a<=max; n++, a++) { for(a=0, n=node; a<=max; n++, a++) {
if (n->type == NODE_TYPE_ACTION) if (n->type == NODE_TYPE_ACTION)
elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION\t(%s,%s)", elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
a, DUMP_THth(n->suffix), DUMP_FM(n->suffix)); a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
else if (n->type == NODE_TYPE_CHAR) else if (n->type == NODE_TYPE_CHAR)
elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character); elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
else if (n->type == NODE_TYPE_END) { else if (n->type == NODE_TYPE_END) {
...@@ -1221,7 +1271,7 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1221,7 +1271,7 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node)
DCH_global_flag |= DCH_F_FX; DCH_global_flag |= DCH_F_FX;
break; break;
} }
return 0; return -1;
} }
/* ---------- /* ----------
...@@ -1245,8 +1295,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -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); tm->tm_hour <13 ? tm->tm_hour : tm->tm_hour-12);
if (S_THth(suf)) if (S_THth(suf))
str_numth(p_inout, inout, 0); str_numth(p_inout, inout, 0);
if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; if (S_FM(suf) || S_THth(suf))
else return 1; return strlen(p_inout)-1;
else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_hour); sscanf(inout, "%d", &tm->tm_hour);
...@@ -1255,15 +1308,18 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1255,15 +1308,18 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
sscanf(inout, "%02d", &tm->tm_hour); sscanf(inout, "%02d", &tm->tm_hour);
return 1 + SKIP_THth(suf); return 1 + SKIP_THth(suf);
} }
} }
case DCH_HH24: case DCH_HH24:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour); sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour);
if (S_THth(suf)) if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; if (S_FM(suf) || S_THth(suf))
else return 1; return strlen(p_inout) -1;
else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_hour); sscanf(inout, "%d", &tm->tm_hour);
...@@ -1273,13 +1329,17 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1273,13 +1329,17 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
return 1 + SKIP_THth(suf); return 1 + SKIP_THth(suf);
} }
} }
case DCH_MI: case DCH_MI:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_min); sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_min);
if (S_THth(suf)) if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; if (S_FM(suf) || S_THth(suf))
else return 1; return strlen(p_inout)-1;
else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_min); sscanf(inout, "%d", &tm->tm_min);
...@@ -1294,8 +1354,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -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); sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_sec);
if (S_THth(suf)) if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) return strlen(p_inout)-1; if (S_FM(suf) || S_THth(suf))
else return 1; return strlen(p_inout) -1;
else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_sec); sscanf(inout, "%d", &tm->tm_sec);
...@@ -1314,14 +1377,14 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout)-1; return strlen(p_inout)-1;
} else if (flag == FROM_CHAR) } 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) { \ #define CHECK_SEQ_SEARCH(_l, _s) { \
if (_l <= 0) { \ 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) ...@@ -1382,28 +1445,40 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
case DCH_MONTH: case DCH_MONTH:
strcpy(inout, months_full[ tm->tm_mon - 1]); strcpy(inout, months_full[ tm->tm_mon - 1]);
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout)); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout));
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_Month: case DCH_Month:
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]);
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_month: case DCH_month:
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[ tm->tm_mon -1 ]);
*inout = tolower(*inout); *inout = tolower(*inout);
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_MON: case DCH_MON:
strcpy(inout, months[ tm->tm_mon -1 ]); strcpy(inout, months[ tm->tm_mon -1 ]);
inout = str_toupper(inout); inout = str_toupper(inout);
return 2; return 2;
case DCH_Mon: case DCH_Mon:
strcpy(inout, months[ tm->tm_mon -1 ]); strcpy(inout, months[ tm->tm_mon -1 ]);
return 2; return 2;
case DCH_mon: case DCH_mon:
strcpy(inout, months[ tm->tm_mon -1 ]); strcpy(inout, months[ tm->tm_mon -1 ]);
*inout = tolower(*inout); *inout = tolower(*inout);
return 2; return 2;
case DCH_MM: case DCH_MM:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mon ); 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) ...@@ -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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) if (S_FM(suf) || S_THth(suf))
return strlen(p_inout)-1; return strlen(p_inout)-1;
else return 1; else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_mon); sscanf(inout, "%d", &tm->tm_mon);
...@@ -1419,33 +1496,46 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1419,33 +1496,46 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} else { } else {
sscanf(inout, "%02d", &tm->tm_mon); sscanf(inout, "%02d", &tm->tm_mon);
return 1 + SKIP_THth(suf); return 1 + SKIP_THth(suf);
} }
} }
case DCH_DAY: case DCH_DAY:
strcpy(inout, days[ tm->tm_wday ]); strcpy(inout, days[ tm->tm_wday ]);
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout)); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, str_toupper(inout));
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_Day: case DCH_Day:
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]);
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_day: case DCH_day:
sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]); sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[ tm->tm_wday]);
*inout = tolower(*inout); *inout = tolower(*inout);
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 8; return strlen(p_inout)-1;
else
return 8;
case DCH_DY: case DCH_DY:
strcpy(inout, days[ tm->tm_wday]); strcpy(inout, days[ tm->tm_wday]);
inout = str_toupper(inout); inout = str_toupper(inout);
return 2; return 2;
case DCH_Dy: case DCH_Dy:
strcpy(inout, days[ tm->tm_wday]); strcpy(inout, days[ tm->tm_wday]);
return 2; return 2;
case DCH_dy: case DCH_dy:
strcpy(inout, days[ tm->tm_wday]); strcpy(inout, days[ tm->tm_wday]);
*inout = tolower(*inout); *inout = tolower(*inout);
return 2; return 2;
case DCH_DDD: case DCH_DDD:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, tm->tm_yday); 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) ...@@ -1454,6 +1544,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
if (S_FM(suf) || S_THth(suf)) if (S_FM(suf) || S_THth(suf))
return strlen(p_inout)-1; return strlen(p_inout)-1;
else return 2; else return 2;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_yday); sscanf(inout, "%d", &tm->tm_yday);
...@@ -1463,6 +1554,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1463,6 +1554,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
return 2 + SKIP_THth(suf); return 2 + SKIP_THth(suf);
} }
} }
case DCH_DD: case DCH_DD:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mday); 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) ...@@ -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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) if (S_FM(suf) || S_THth(suf))
return strlen(p_inout)-1; return strlen(p_inout)-1;
else return 1; else
return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
if (S_FM(suf)) { if (S_FM(suf)) {
sscanf(inout, "%d", &tm->tm_mday); sscanf(inout, "%d", &tm->tm_mday);
...@@ -1483,16 +1577,17 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1483,16 +1577,17 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
case DCH_D: case DCH_D:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%d", tm->tm_wday+1); sprintf(inout, "%d", tm->tm_wday+1);
if (S_THth(suf)) if (S_THth(suf)) {
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return 2; return 2;
}
return 0; return 0;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
sscanf(inout, "%1d", &tm->tm_wday); sscanf(inout, "%1d", &tm->tm_wday);
if(tm->tm_wday) --tm->tm_wday; if(tm->tm_wday) --tm->tm_wday;
return 0 + SKIP_THth(suf); return 0 + SKIP_THth(suf);
} }
case DCH_WW: case DCH_WW:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, 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) ...@@ -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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_FM(suf) || S_THth(suf)) if (S_FM(suf) || S_THth(suf))
return strlen(p_inout)-1; return strlen(p_inout)-1;
else return 1; else
return 1;
} else if (flag == FROM_CHAR) } 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: case DCH_Q:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%d", (tm->tm_mon-1)/3+1); 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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return 2; return 2;
}
return 0; return 0;
} else if (flag == FROM_CHAR) } 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: case DCH_CC:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
i = tm->tm_year/100 +1; i = tm->tm_year/100 +1;
...@@ -1524,8 +1623,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1524,8 +1623,9 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
if (S_THth(suf)) if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout)-1; return strlen(p_inout)-1;
} else if (flag == FROM_CHAR) } 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: case DCH_Y_YYY:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
i= YEAR_ABS(tm->tm_year) / 1000; i= YEAR_ABS(tm->tm_year) / 1000;
...@@ -1535,6 +1635,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1535,6 +1635,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
if (tm->tm_year < 0) if (tm->tm_year < 0)
strcat(inout, BC_STR); strcat(inout, BC_STR);
return strlen(p_inout)-1; return strlen(p_inout)-1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
int cc, yy; int cc, yy;
sscanf(inout, "%d,%03d", &cc, &yy); sscanf(inout, "%d,%03d", &cc, &yy);
...@@ -1552,6 +1653,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1552,6 +1653,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
tm->tm_year = tm->tm_year+1; tm->tm_year = tm->tm_year+1;
return len-1; return len-1;
} }
case DCH_YYYY: case DCH_YYYY:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
if (tm->tm_year <= 9999 && tm->tm_year >= -9998) 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) ...@@ -1563,6 +1665,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
if (tm->tm_year < 0) if (tm->tm_year < 0)
strcat(inout, BC_STR); strcat(inout, BC_STR);
return strlen(p_inout)-1; return strlen(p_inout)-1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
sscanf(inout, "%d", &tm->tm_year); sscanf(inout, "%d", &tm->tm_year);
if (!S_FM(suf) && tm->tm_year <= 9999 && tm->tm_year >= -9999) 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) ...@@ -1577,73 +1680,92 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
tm->tm_year = tm->tm_year+1; tm->tm_year = tm->tm_year+1;
return len-1; return len-1;
} }
case DCH_YYY: case DCH_YYY:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(buff, "%03d", YEAR_ABS(tm->tm_year)); sprintf(buff, "%03d", YEAR_ABS(tm->tm_year));
i=strlen(buff); i=strlen(buff);
strcpy(inout, buff+(i-3)); strcpy(inout, buff+(i-3));
if (S_THth(suf)) if (S_THth(suf)) {
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf)) return 4; return 4;
}
return 2; return 2;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
int yy; int yy;
sscanf(inout, "%03d", &yy); sscanf(inout, "%03d", &yy);
tm->tm_year = (tm->tm_year/1000)*1000 +yy; tm->tm_year = (tm->tm_year/1000)*1000 +yy;
return 2 + SKIP_THth(suf); return 2 + SKIP_THth(suf);
} }
case DCH_YY: case DCH_YY:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(buff, "%02d", YEAR_ABS(tm->tm_year)); sprintf(buff, "%02d", YEAR_ABS(tm->tm_year));
i=strlen(buff); i=strlen(buff);
strcpy(inout, buff+(i-2)); strcpy(inout, buff+(i-2));
if (S_THth(suf)) if (S_THth(suf)) {
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf)) return 3; return 3;
}
return 1; return 1;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
int yy; int yy;
sscanf(inout, "%02d", &yy); sscanf(inout, "%02d", &yy);
tm->tm_year = (tm->tm_year/100)*100 +yy; tm->tm_year = (tm->tm_year/100)*100 +yy;
return 1 + SKIP_THth(suf); return 1 + SKIP_THth(suf);
} }
case DCH_Y: case DCH_Y:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(buff, "%1d", YEAR_ABS(tm->tm_year)); sprintf(buff, "%1d", YEAR_ABS(tm->tm_year));
i=strlen(buff); i=strlen(buff);
strcpy(inout, buff+(i-1)); strcpy(inout, buff+(i-1));
if (S_THth(suf)) if (S_THth(suf)) {
str_numth(p_inout, inout, S_TH_TYPE(suf)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf)) return 2; return 2;
}
return 0; return 0;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
int yy; int yy;
sscanf(inout, "%1d", &yy); sscanf(inout, "%1d", &yy);
tm->tm_year = (tm->tm_year/10)*10 +yy; tm->tm_year = (tm->tm_year/10)*10 +yy;
return 0 + SKIP_THth(suf); return 0 + SKIP_THth(suf);
} }
case DCH_RM: case DCH_RM:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%*s", S_FM(suf) ? 0 : -4, sprintf(inout, "%*s", S_FM(suf) ? 0 : -4,
rm_months[ 12 - tm->tm_mon ]); rm_months[ 12 - tm->tm_mon ]);
if (S_FM(suf)) return strlen(p_inout)-1; if (S_FM(suf))
else return 3; return strlen(p_inout)-1;
else
return 3;
} else if (flag == FROM_CHAR) { } else if (flag == FROM_CHAR) {
tm->tm_mon = 11-seq_search(inout, rm_months, ALL_UPPER, FULL_SIZ, &len); tm->tm_mon = 11-seq_search(inout, rm_months, ALL_UPPER, FULL_SIZ, &len);
CHECK_SEQ_SEARCH(len, "RM"); CHECK_SEQ_SEARCH(len, "RM");
++tm->tm_mon; ++tm->tm_mon;
if (S_FM(suf)) return len-1; if (S_FM(suf))
else return 3; return len-1;
else
return 3;
} }
case DCH_W: case DCH_W:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%d", (tm->tm_mday - tm->tm_wday +7) / 7 ); 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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf)) return 2; return 2;
}
return 0; return 0;
} else if (flag == FROM_CHAR) } 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: case DCH_J:
if (flag == TO_CHAR) { if (flag == TO_CHAR) {
sprintf(inout, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); 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) ...@@ -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)); str_numth(p_inout, inout, S_TH_TYPE(suf));
return strlen(p_inout)-1; return strlen(p_inout)-1;
} else if (flag == FROM_CHAR) } 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) ...@@ -1699,7 +1821,7 @@ datetime_to_char(DateTime *dt, text *fmt)
datetime2tm(SetDateTime(*dt), &tz, tm, &fsec, &tzn); datetime2tm(SetDateTime(*dt), &tz, tm, &fsec, &tzn);
} else { } else {
if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) != 0) 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; 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) ...@@ -1756,20 +1878,20 @@ datetime_to_char(DateTime *dt, text *fmt)
*/ */
strncpy(CacheStr, str, DCH_CACHE_SIZE); strncpy(CacheStr, str, DCH_CACHE_SIZE);
parse_format(CacheFormat, str, DCH_keywords,
DCH_suff, DCH_index, DCH_TYPE, NULL);
#ifdef DEBUG_TO_FROM_CHAR #ifdef DEBUG_TO_FROM_CHAR
/* dump_node(CacheFormat, len); */ /* dump_node(CacheFormat, len); */
/* dump_index(DCH_keywords, DCH_index); */ /* dump_index(DCH_keywords, DCH_index); */
#endif #endif
parse_format(CacheFormat, str, DCH_keywords,
DCH_suff, DCH_index, DCH_TYPE, NULL);
(CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */
} }
format = CacheFormat; format = CacheFormat;
} }
DCH_action(format, VARDATA(result), TO_CHAR); DCH_processor(format, VARDATA(result), TO_CHAR);
if (flag) if (flag)
pfree(format); pfree(format);
...@@ -1888,7 +2010,7 @@ to_datetime(text *date_str, text *fmt) ...@@ -1888,7 +2010,7 @@ to_datetime(text *date_str, text *fmt)
/* dump_node(format, len); */ /* dump_node(format, len); */
#endif #endif
VARDATA(date_str)[ VARSIZE(date_str) - VARHDRSZ ] = '\0'; 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); pfree(str);
...@@ -1939,7 +2061,7 @@ to_datetime(text *date_str, text *fmt) ...@@ -1939,7 +2061,7 @@ to_datetime(text *date_str, text *fmt)
NOTICE_TM; NOTICE_TM;
#endif #endif
if (tm2datetime(tm, fsec, &tz, result) != 0) 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; return result;
} }
...@@ -2012,9 +2134,13 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, ...@@ -2012,9 +2134,13 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat,
Num->flag = 0; Num->flag = 0;
Num->lsign = 0; Num->lsign = 0;
Num->pre = 0; Num->pre = 0;
Num->pos = 0; Num->post = 0;
Num->pre_lsign_num = 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, parse_format(format, str, NUM_keywords,
NULL, NUM_index, NUM_TYPE, Num); NULL, NUM_index, NUM_TYPE, Num);
...@@ -2051,17 +2177,20 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, ...@@ -2051,17 +2177,20 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat,
CacheNum->flag = 0; CacheNum->flag = 0;
CacheNum->lsign = 0; CacheNum->lsign = 0;
CacheNum->pre = 0; CacheNum->pre = 0;
CacheNum->pos = 0; CacheNum->post = 0;
CacheNum->pre_lsign_num = 0; CacheNum->pre_lsign_num = 0;
CacheNum->need_locale = 0; CacheNum->need_locale = 0;
CacheNum->multi = 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 #ifdef DEBUG_TO_FROM_CHAR
/* dump_node(CacheFormat, len); */ /* dump_node(CacheFormat, len); */
/* dump_index(NUM_keywords, NUM_index); */ /* dump_index(NUM_keywords, NUM_index); */
#endif #endif
parse_format(CacheFormat, str, NUM_keywords,
NULL, NUM_index, NUM_TYPE, CacheNum);
(CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */ (CacheFormat + len)->type = NODE_TYPE_END; /* Paranoa? */
} }
...@@ -2072,10 +2201,12 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat, ...@@ -2072,10 +2201,12 @@ NUM_cache( int len, char *CacheStr, FormatNode *CacheFormat,
Num->flag = CacheNum->flag; Num->flag = CacheNum->flag;
Num->lsign = CacheNum->lsign; Num->lsign = CacheNum->lsign;
Num->pre = CacheNum->pre; Num->pre = CacheNum->pre;
Num->pos = CacheNum->pos; Num->post = CacheNum->post;
Num->pre_lsign_num = CacheNum->pre_lsign_num; Num->pre_lsign_num = CacheNum->pre_lsign_num;
Num->need_locale = CacheNum->need_locale; Num->need_locale = CacheNum->need_locale;
Num->multi = CacheNum->multi; Num->multi = CacheNum->multi;
Num->zero_start = CacheNum->zero_start;
Num->zero_end = CacheNum->zero_end;
pfree(str); pfree(str);
return CacheFormat; return CacheFormat;
...@@ -2210,213 +2341,332 @@ NUM_prepare_locale(NUMProc *Np) ...@@ -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) { \ static char *
if ((_np)->sign_wrote==0) { \ get_last_relevant_decnum(char *num)
if (IS_BRACKET((_np)->Num)) { \ {
\ char *result,
*(_np)->inout_p = '<'; \ *p = strchr(num, '.');
++(_np)->inout_p; \
(_np)->sign_wrote = 1; \ elog(NOTICE, "CALL: get_last_relevant_decnum()");
\
} else if ((_np)->Num->lsign==NUM_LSIGN_PRE && (! IS_BRACKET((_np)->Num)) && \ if (!p)
(! IS_MINUS((_np)->Num)) && (! IS_PLUS((_np)->Num))) { \ p = num;
\ result = p;
if ((_np)->sign=='-') \
strcpy((_np)->inout_p, (_np)->L_negative_sign); \ while(*(++p)) {
else \ if (*p!='0')
strcpy((_np)->inout_p, (_np)->L_positive_sign); \ result = p;
(_np)->inout_p += strlen((_np)->inout_p); \ }
(_np)->sign_wrote = 1; \
\ return result;
} 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; \
} \
} \
} \
} }
/* ---------- /* ----------
* Create number * Number extraction for TO_NUMBER()
* return FALSE if any work over current NUM_[0|9|D|DEC] must be skip
* in NUM_processor()
* ---------- * ----------
*/ */
static int static void
NUM_numpart(NUMProc *Np, int id) NUM_numpart_from_char(NUMProc *Np, int id)
{ {
if (IS_ROMAN(Np->Num))
return FALSE; #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, " --- scan start --- ");
/* Note: in this elog() output not set '\0' in inout #endif
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); if (*Np->inout_p == ' ')
*/ Np->inout_p++;
/* ---------- /* ----------
* Number extraction for TO_NUMBER() * read sign
* ---------- * ----------
*/ */
if (Np->type == FROM_CHAR) { if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9 || NUM_S)) {
if (id == NUM_9 || id == NUM_0) {
if (!*(Np->number+1)) { #ifdef DEBUG_TO_FROM_CHAR
if (*Np->inout_p == '-' || elog(DEBUG_elog_output, "Try read sign (%c).", *Np->inout_p);
(IS_BRACKET(Np->Num) && #endif
*Np->inout_p == '<' )) { /* ----------
* locale sign
*Np->number = '-'; * ----------
Np->inout_p++; */
if (IS_LSIGN(Np->Num)) {
} else if (*Np->inout_p == '+') {
int x = strlen(Np->L_negative_sign);
*Np->number = '+';
Np->inout_p++; #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, "Try read locale sign (%c).", *Np->inout_p);
} else if (*Np->inout_p == ' ' && (! IS_FILLMODE(Np->Num))) { #endif
Np->inout_p++; 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; x = strlen(Np->L_positive_sign);
Np->number_p++; if (!strncmp(Np->inout_p, Np->L_positive_sign, x)) {
} Np->inout_p += x-1;
} else { *Np->number = '+';
if (id == NUM_DEC) { return;
*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++;
}
} }
} }
return TRUE;
}
/* ---------- #ifdef DEBUG_TO_FROM_CHAR
* Add blank space (pre number) elog(DEBUG_elog_output, "Try read sipmle sign (%c).", *Np->inout_p);
* ---------- #endif
*/ /* ----------
if ((! IS_ZERO(Np->Num)) && (! IS_FILLMODE(Np->Num)) && Np->pre_number > 0) { * simple + - < >
*Np->inout_p = ' '; * ----------
--Np->pre_number; */
--Np->count_num; if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
return TRUE; *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) { if (isdigit((unsigned char) *Np->inout_p)) {
SET_SIGN(Np); if (Np->read_dec && Np->read_post == Np->Num->post)
*Np->inout_p='0'; return;
--Np->pre_number;
--Np->count_num; *Np->number_p = *Np->inout_p;
return TRUE; Np->number_p++;
}
if (IS_FILLMODE(Np->Num) && Np->pre_number > 0) { if (Np->read_dec)
--Np->pre_number; Np->read_post++;
return FALSE;
} #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) { } else if (IS_DECIMAL(Np->Num)) {
SET_SIGN(Np);
#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=='.') { if (Np->num_curr == Np->sign_pos && Np->sign_wrote==FALSE) {
strcpy(Np->inout_p, Np->decimal);
Np->inout_p += strlen(Np->inout_p); #ifdef DEBUG_TO_FROM_CHAR
if (*Np->number_p) elog(DEBUG_elog_output, "Writing sign to position: %d", Np->num_curr);
++Np->number_p; #endif
return FALSE; if (IS_LSIGN(Np->Num)) {
}
if (*Np->number_p) {
/* ----------
* Copy number string to inout string
* ----------
*/
*Np->inout_p = *Np->number_p;
++Np->number_p;
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) { #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, "Writing bracket to position %d", Np->num_curr);
if (IS_BRACKET(Np->Num)) { #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->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; * Write ZERO
if (Np->sign=='-') * ----------
strcpy(Np->inout_p, Np->L_negative_sign); */
else #ifdef DEBUG_TO_FROM_CHAR
strcpy(Np->inout_p, Np->L_positive_sign); elog(DEBUG_elog_output, "Writing zero to position %d", Np->num_curr);
Np->inout_p += strlen(Np->inout_p)-1; #endif
Np->sign_wrote = 1; *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;
}
} }
} ++Np->number_p;
} else }
return FALSE; }
return TRUE;
++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 * static char *
NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
int plen, int sign, int type) int plen, int sign, int type)
...@@ -2427,32 +2677,24 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2427,32 +2677,24 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
Np->Num = Num; Np->Num = Num;
Np->type = type; Np->type = type;
Np->number = number; 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->inout = inout;
Np->last_relevant = NULL;
Np->sign_wrote = Np->count_num = Np->in_number = 0; 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 (IS_ROMAN(Np->Num)) {
if (Np->type==FROM_CHAR) 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->lsign = Np->Num->pre_lsign_num = Np->Num->post =
Np->Num->pre = Np->pre_number = Np->sign = 0; Np->Num->pre = Np->num_pre = Np->sign = 0;
if (IS_FILLMODE(Np->Num)){ if (IS_FILLMODE(Np->Num)){
Np->Num->flag = 0; Np->Num->flag = 0;
...@@ -2462,37 +2704,128 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2462,37 +2704,128 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
} }
Np->Num->flag |= NUM_F_ROMAN; Np->Num->flag |= NUM_F_ROMAN;
} }
/* ---------- /* ----------
* Check Num struct * Sign
* ---------- * ----------
*/ */
if (Np->sign=='+') if (type == FROM_CHAR) {
Np->Num->flag &= ~NUM_F_BRACKET; 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) if (Np->sign=='+' && IS_FILLMODE(Np->Num) && !IS_LSIGN(Np->Num))
Np->Num->lsign = NUM_LSIGN_POST; Np->sign_wrote = TRUE; /* needn't sign */
else
Np->sign_wrote = FALSE; /* need sign */
/* set counter (number of all digits) */ Np->sign_pos = -1;
Np->count_num = Np->Num->pos + Np->Num->pre;
if (Np->type==TO_CHAR && IS_FILLMODE(Np->Num) && (! IS_ZERO(Np->Num))) if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
Np->count_num -= Np->pre_number; 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 #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, "NUM: '%s', PRE: %d, POS: %d, PLEN: %d, LSIGN: %d, DECIMAL: %d, MULTI: %d", elog(DEBUG_elog_output,
Np->number, Np->Num->pre, Np->Num->pos,
Np->pre_number, Np->Num->lsign,IS_DECIMAL(Np->Num), "\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->Num->multi); 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 : "<not set>"
);
#endif #endif
/* ---------- /* ----------
* Locale * Locale
* ---------- * ----------
*/ */
NUM_prepare_locale(Np); NUM_prepare_locale(Np);
/* need for DEBUG: memset(Np->inout, '\0', Np->count_num );*/
/* ---------- /* ----------
* Processor direct cycle * Processor direct cycle
* ---------- * ----------
...@@ -2501,7 +2834,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -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 */ Np->number_p=Np->number+1; /* first char is space for sign */
else if (Np->type == TO_CHAR) else if (Np->type == TO_CHAR)
Np->number_p=Np->number; Np->number_p=Np->number;
for(n=node, Np->inout_p=Np->inout; n->type != NODE_TYPE_END; n++) { for(n=node, Np->inout_p=Np->inout; n->type != NODE_TYPE_END; n++) {
if (Np->type == FROM_CHAR) { if (Np->type == FROM_CHAR) {
...@@ -2529,15 +2862,19 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2529,15 +2862,19 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
case NUM_0: case NUM_0:
case NUM_DEC: case NUM_DEC:
case NUM_D: case NUM_D:
case NUM_S:
if (NUM_numpart(Np, n->key->id)) case NUM_PR:
break; if (Np->type == TO_CHAR) {
else NUM_numpart_to_char(Np, n->key->id);
continue; continue; /* for() */
} else {
NUM_numpart_from_char(Np, n->key->id);
break; /* switch() case: */
}
case NUM_COMMA: case NUM_COMMA:
if (Np->type == TO_CHAR) { if (Np->type == TO_CHAR) {
if (!Np->in_number) { if (!Np->num_in) {
if (IS_FILLMODE(Np->Num)) if (IS_FILLMODE(Np->Num))
continue; continue;
else else
...@@ -2546,7 +2883,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2546,7 +2883,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
*Np->inout_p = ','; *Np->inout_p = ',';
} else if (Np->type == FROM_CHAR) { } else if (Np->type == FROM_CHAR) {
if (!Np->in_number) { if (!Np->num_in) {
if (IS_FILLMODE(Np->Num)) if (IS_FILLMODE(Np->Num))
continue; continue;
} }
...@@ -2555,7 +2892,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2555,7 +2892,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
case NUM_G: case NUM_G:
if (Np->type == TO_CHAR) { if (Np->type == TO_CHAR) {
if (!Np->in_number) { if (!Np->num_in) {
if (IS_FILLMODE(Np->Num)) if (IS_FILLMODE(Np->Num))
continue; continue;
else { else {
...@@ -2569,7 +2906,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2569,7 +2906,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
} }
} else if (Np->type == FROM_CHAR) { } else if (Np->type == FROM_CHAR) {
if (!Np->in_number) { if (!Np->num_in) {
if (IS_FILLMODE(Np->Num)) if (IS_FILLMODE(Np->Num))
continue; continue;
} }
...@@ -2587,69 +2924,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2587,69 +2924,7 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
} }
break; 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: case NUM_RN:
if (Np->type == FROM_CHAR)
elog(ERROR, "TO_NUMBER: internal error #1");
if (IS_FILLMODE(Np->Num)) { if (IS_FILLMODE(Np->Num)) {
strcpy(Np->inout_p, Np->number_p); strcpy(Np->inout_p, Np->number_p);
Np->inout_p += strlen(Np->inout_p) - 1; Np->inout_p += strlen(Np->inout_p) - 1;
...@@ -2658,9 +2933,6 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2658,9 +2933,6 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
break; break;
case NUM_rn: case NUM_rn:
if (Np->type == FROM_CHAR)
elog(ERROR, "TO_NUMBER: internal error #2");
if (IS_FILLMODE(Np->Num)) { if (IS_FILLMODE(Np->Num)) {
strcpy(Np->inout_p, str_tolower(Np->number_p)); strcpy(Np->inout_p, str_tolower(Np->number_p));
Np->inout_p += strlen(Np->inout_p) - 1; Np->inout_p += strlen(Np->inout_p) - 1;
...@@ -2688,29 +2960,45 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2688,29 +2960,45 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
Np->inout_p += 1; Np->inout_p += 1;
break; break;
case NUM_S: case NUM_MI:
/* ---------- if (Np->type == TO_CHAR) {
* 'S' for TO_CHAR is in NUM_numpart() if (Np->sign=='-')
* ---------- *Np->inout_p = '-';
*/ else
if (Np->type == FROM_CHAR && Np->sign_wrote==FALSE) { *Np->inout_p = ' ';
int x = strlen(Np->L_negative_sign); } else if (Np->type == FROM_CHAR) {
if (!strncmp(Np->inout_p, Np->L_negative_sign, x)) { if (*Np->inout_p == '-')
Np->inout_p += x-1;
*Np->number = '-'; *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; 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: default:
continue; continue;
break; break;
...@@ -2729,16 +3017,29 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, ...@@ -2729,16 +3017,29 @@ NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number,
if (Np->type == TO_CHAR) { if (Np->type == TO_CHAR) {
*Np->inout_p = '\0'; *Np->inout_p = '\0';
return Np->inout; return Np->inout;
} else if (Np->type == FROM_CHAR) { } 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 #ifdef DEBUG_TO_FROM_CHAR
elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number); elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
#endif #endif
return Np->number; return Np->number;
} else } else
return NULL; return NULL;
return NULL;
} }
/* ---------- /* ----------
...@@ -2811,7 +3112,7 @@ numeric_to_number(text *value, text *fmt) ...@@ -2811,7 +3112,7 @@ numeric_to_number(text *value, text *fmt)
NUM_processor(format, &Num, VARDATA(value), numstr, NUM_processor(format, &Num, VARDATA(value), numstr,
VARSIZE(value) - VARHDRSZ, 0, FROM_CHAR); VARSIZE(value) - VARHDRSZ, 0, FROM_CHAR);
scale = Num.pos; scale = Num.post;
precision = MAX(0, Num.pre) + scale; precision = MAX(0, Num.pre) + scale;
return numeric_in(numstr, 0, ((precision << 16) | scale) + VARHDRSZ); return numeric_in(numstr, 0, ((precision << 16) | scale) + VARHDRSZ);
...@@ -2853,7 +3154,7 @@ numeric_to_char(Numeric value, text *fmt) ...@@ -2853,7 +3154,7 @@ numeric_to_char(Numeric value, text *fmt)
Num.pre += Num.multi; Num.pre += Num.multi;
} }
orgnum = numeric_out( numeric_round(val, Num.pos) ); orgnum = numeric_out( numeric_round(val, Num.post) );
if (*orgnum == '-') { /* < 0 */ if (*orgnum == '-') { /* < 0 */
sign = '-'; sign = '-';
numstr = orgnum+1; numstr = orgnum+1;
...@@ -2872,10 +3173,10 @@ numeric_to_char(Numeric value, text *fmt) ...@@ -2872,10 +3173,10 @@ numeric_to_char(Numeric value, text *fmt)
else if (len > Num.pre) { else if (len > Num.pre) {
fill_str(numstr, '#', Num.pre); fill_str(numstr, '#', Num.pre);
*(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; NUM_TOCHAR_finish;
return result; return result;
} }
...@@ -2921,16 +3222,16 @@ int4_to_char(int32 value, text *fmt) ...@@ -2921,16 +3222,16 @@ int4_to_char(int32 value, text *fmt)
} else } else
sign = '+'; sign = '+';
if (Num.pos) { if (Num.post) {
int i; int i;
numstr = palloc( len + 1 + Num.pos ); numstr = palloc( len + 1 + Num.post );
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
*(numstr + len) = '.'; *(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+i) = '0';
*(numstr + Num.pos + len + 1) = '\0'; *(numstr + Num.post + len + 1) = '\0';
pfree(orgnum); pfree(orgnum);
orgnum = numstr; orgnum = numstr;
} else } else
...@@ -2941,12 +3242,10 @@ int4_to_char(int32 value, text *fmt) ...@@ -2941,12 +3242,10 @@ int4_to_char(int32 value, text *fmt)
else if (len > Num.pre) { else if (len > Num.pre) {
fill_str(numstr, '#', Num.pre); fill_str(numstr, '#', Num.pre);
*(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; NUM_TOCHAR_finish;
return result; return result;
} }
...@@ -2993,16 +3292,16 @@ int8_to_char(int64 *value, text *fmt) ...@@ -2993,16 +3292,16 @@ int8_to_char(int64 *value, text *fmt)
} else } else
sign = '+'; sign = '+';
if (Num.pos) { if (Num.post) {
int i; int i;
numstr = palloc( len + 1 + Num.pos ); numstr = palloc( len + 1 + Num.post );
strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0)); strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
*(numstr + len) = '.'; *(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+i) = '0';
*(numstr + Num.pos + len + 1) = '\0'; *(numstr + Num.post + len + 1) = '\0';
pfree(orgnum); pfree(orgnum);
orgnum = numstr; orgnum = numstr;
} else } else
...@@ -3013,7 +3312,7 @@ int8_to_char(int64 *value, text *fmt) ...@@ -3013,7 +3312,7 @@ int8_to_char(int64 *value, text *fmt)
else if (len > Num.pre) { else if (len > Num.pre) {
fill_str(numstr, '#', Num.pre); fill_str(numstr, '#', Num.pre);
*(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) ...@@ -3058,10 +3357,10 @@ float4_to_char(float32 value, text *fmt)
if (Num.pre > len) if (Num.pre > len)
plen = Num.pre - len; plen = Num.pre - len;
if (len >= FLT_DIG) if (len >= FLT_DIG)
Num.pos = 0; Num.post = 0;
else if (Num.pos + len > FLT_DIG) else if (Num.post + len > FLT_DIG)
Num.pos = FLT_DIG - len; Num.post = FLT_DIG - len;
sprintf(orgnum, "%.*f", Num.pos, *val); sprintf(orgnum, "%.*f", Num.post, *val);
if (*orgnum == '-') { /* < 0 */ if (*orgnum == '-') { /* < 0 */
sign = '-'; sign = '-';
...@@ -3081,7 +3380,7 @@ float4_to_char(float32 value, text *fmt) ...@@ -3081,7 +3380,7 @@ float4_to_char(float32 value, text *fmt)
else if (len > Num.pre) { else if (len > Num.pre) {
fill_str(numstr, '#', Num.pre); fill_str(numstr, '#', Num.pre);
*(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) ...@@ -3125,10 +3424,10 @@ float8_to_char(float64 value, text *fmt)
if (Num.pre > len) if (Num.pre > len)
plen = Num.pre - len; plen = Num.pre - len;
if (len >= DBL_DIG) if (len >= DBL_DIG)
Num.pos = 0; Num.post = 0;
else if (Num.pos + len > DBL_DIG) else if (Num.post + len > DBL_DIG)
Num.pos = DBL_DIG - len; Num.post = DBL_DIG - len;
sprintf(orgnum, "%.*f", Num.pos, *val); sprintf(orgnum, "%.*f", Num.post, *val);
if (*orgnum == '-') { /* < 0 */ if (*orgnum == '-') { /* < 0 */
sign = '-'; sign = '-';
...@@ -3148,7 +3447,7 @@ float8_to_char(float64 value, text *fmt) ...@@ -3148,7 +3447,7 @@ float8_to_char(float64 value, text *fmt)
else if (len > Num.pre) { else if (len > Num.pre) {
fill_str(numstr, '#', Num.pre); fill_str(numstr, '#', Num.pre);
*(numstr + Num.pre) = '.'; *(numstr + Num.pre) = '.';
fill_str(numstr + 1 + Num.pre, '#', Num.pos); fill_str(numstr + 1 + Num.pre, '#', Num.post);
} }
} }
......
/*------ /* -----------------------------------------------------------------------
* pg_locale.c * 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 <stdio.h> #include <stdio.h>
......
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.h * 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, * The PostgreSQL routines for a DateTime/int/float/numeric formatting,
* inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * inspire with Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
* *
* 1999 Karel Zak "Zakkr" * Karel Zak - Zakkr
* *
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
*/ */
......
/*------ /* -----------------------------------------------------------------------
* pg_locale.h * 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_ #ifndef _PG_LOCALE_
#define _PG_LOCALE_ #define _PG_LOCALE_
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment