Commit 2a34134b authored by Bruce Momjian's avatar Bruce Momjian

- new to_char(interval, text)

 - new millisecond (ms) and microsecond (us) support
 - more robus parsing from string - used is separator checking for
   non-exact formats like to_date('2001-9-1', 'YYYY-MM-DD')
 - SGML docs are included

Karel Zak
parent 74dde13e
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.68 2001/08/31 07:45:09 ishii Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.69 2001/09/06 03:22:41 momjian Exp $ -->
<chapter id="functions"> <chapter id="functions">
<title>Functions and Operators</title> <title>Functions and Operators</title>
...@@ -1564,6 +1564,12 @@ ...@@ -1564,6 +1564,12 @@
<entry>convert timestamp to string</entry> <entry>convert timestamp to string</entry>
<entry>to_char(timestamp 'now','HH12:MI:SS')</entry> <entry>to_char(timestamp 'now','HH12:MI:SS')</entry>
</row> </row>
<row>
<entry>to_char(interval, text)</entry>
<entry>text</entry>
<entry>convert interval to string</entry>
<entry>to_char(interval '15h 2m 12s','HH24:MI:SS')</entry>
</row>
<row> <row>
<entry>to_char(int, text)</entry> <entry>to_char(int, text)</entry>
<entry>text</entry> <entry>text</entry>
...@@ -1645,6 +1651,14 @@ ...@@ -1645,6 +1651,14 @@
<entry>SS</entry> <entry>SS</entry>
<entry>second (00-59)</entry> <entry>second (00-59)</entry>
</row> </row>
<row>
<entry>MS</entry>
<entry>millisecond (000-999)</entry>
</row>
<row>
<entry>US</entry>
<entry>microsecond (000000-999999)</entry>
</row>
<row> <row>
<entry>SSSS</entry> <entry>SSSS</entry>
<entry>seconds past midnight (0-86399)</entry> <entry>seconds past midnight (0-86399)</entry>
...@@ -1911,6 +1925,23 @@ ...@@ -1911,6 +1925,23 @@
<literal>to_date('20000Nov31', 'YYYYMonDD')</literal>. <literal>to_date('20000Nov31', 'YYYYMonDD')</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
Millisecond <literal>MS</literal> and microcesond <literal>US</literal>
values are in conversion from string to timestamp used as part of
second after decimal point. For example
<literal>to_timestamp('12:3', 'SS:MS')</literal> is not 3 milliseconds,
but 300, because the conversion count it as <literal>12 + 0.3</literal>.
It means for format 'SS:MS' is '12:3' or '12:30' or '12:300' same
number of miliceconds. For the three milliseconds must be used
'12:003' that the counversion count as
<literal> 12 + 0.003 = 12.003 seconds </literal>. Here is a more
complex example:
<literal>to_timestamp('15:12:02.020.001230','HH:MI:SS.MS.US')</literal>
is 15 hours, 12 minutes, 2.021230 seconds.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</para> </para>
......
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.c * formatting.c
* *
* $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.38 2001/06/25 21:11:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.39 2001/09/06 03:22:42 momjian Exp $
* *
* *
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group * Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
...@@ -44,8 +44,7 @@ ...@@ -44,8 +44,7 @@
* *
* Karel Zak * Karel Zak
* *
* TODO (7.2): * TODO
* - replace some global values by struct that handle it
* - check last used entry in the cache_search * - check last used entry in the cache_search
* - better number building (formatting) * - better number building (formatting)
* - add support for abstime * - add support for abstime
...@@ -370,43 +369,59 @@ typedef struct ...@@ -370,43 +369,59 @@ typedef struct
dd, dd,
ddd, ddd,
mm, mm,
ms,
yyyy, yyyy,
yyy, yyy,
yy, yy,
y, y,
bc, bc,
iw, iw,
ww, ww,
w, w,
cc, cc,
q, q,
j; j,
us;
} TmFromChar; } TmFromChar;
#define ZERO_tmfc( _X ) \ #define ZERO_tmfc( _X ) memset(_X, 0, sizeof(TmFromChar))
do { \
(_X)->hh= (_X)->am= (_X)->pm= (_X)->mi= (_X)->ss= (_X)->ssss= \
(_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->yyy= \
(_X)->yy= (_X)->y= (_X)->bc= (_X)->iw= (_X)->ww= (_X)->w= \
(_X)->cc= (_X)->q= (_X)->j= 0; \
} while(0)
/* ----------
* Debug
* ----------
*/
#ifdef DEBUG_TO_FROM_CHAR #ifdef DEBUG_TO_FROM_CHAR
#define DEBUG_TMFC( _X ) \
#define NOTICE_TMFC \ elog(DEBUG_elog_output, "TMFC:\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyyyy %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d\nus: %d", \
elog(DEBUG_elog_output, "TMFC:\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nyyyy %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d", \ (_X)->hh, (_X)->am, (_X)->pm, (_X)->mi, (_X)->ss, \
tmfc->hh, tmfc->am, tmfc->pm, tmfc->mi, tmfc->ss, \ (_X)->ssss, (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, \
tmfc->ssss, tmfc->d, tmfc->dd, tmfc->ddd, tmfc->mm, \ (_X)->yyyy, (_X)->bc, (_X)->iw, (_X)->ww, (_X)->w, \
tmfc->yyyy, tmfc->bc, tmfc->iw, tmfc->ww, tmfc->w, \ (_X)->cc, (_X)->q, (_X)->j, (_X)->us);
tmfc->cc, tmfc->q, tmfc->j); #define DEBUG_TM( _X ) \
#define NOTICE_TM \
elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\ elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
tm->tm_sec, tm->tm_year,\ (_X)->tm_sec, (_X)->tm_year,\
tm->tm_min, tm->tm_wday, tm->tm_hour, tm->tm_yday,\ (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
tm->tm_mday, tm->tm_isdst, tm->tm_mon) (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
#else
#define DEBUG_TMFC( _X )
#define DEBUG_TM( _X )
#endif #endif
/* ----------
* Datetime to char conversion
* ----------
*/
typedef struct TmToChar
{
struct tm tm; /* classic 'tm' struct */
double fsec; /* milliseconds */
char *tzn; /* timezone */
} TmToChar;
#define tmtcTm(_X) (&(_X)->tm)
#define tmtcTzn(_X) ((_X)->tzn)
#define tmtcFsec(_X) ((_X)->fsec)
#define ZERO_tm( _X ) \ #define ZERO_tm( _X ) \
do { \ do { \
(_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \ (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
...@@ -414,15 +429,12 @@ typedef struct ...@@ -414,15 +429,12 @@ typedef struct
(_X)->tm_mday = (_X)->tm_mon = 1; \ (_X)->tm_mday = (_X)->tm_mon = 1; \
} while(0) } while(0)
/* ---------- #define ZERO_tmtc( _X ) \
* Private global-modul definitions do { \
* ---------- ZERO_tm( tmtcTm(_X) ); \
*/ tmtcFsec(_X) = 0; \
static struct tm _tm, tmtcTzn(_X) = NULL; \
*tm = &_tm; } while(0)
static TmFromChar _tmfc,
*tmfc = &_tmfc;
static char *tzn;
/* ---------- /* ----------
* Utils * Utils
...@@ -439,9 +451,9 @@ static char *tzn; ...@@ -439,9 +451,9 @@ static char *tzn;
* KeyWords definition & action * KeyWords definition & action
*****************************************************************************/ *****************************************************************************/
static int dch_global(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_global(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
static int dch_time(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
static int dch_date(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_date(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
/* ---------- /* ----------
* Suffixes: * Suffixes:
...@@ -532,6 +544,7 @@ typedef enum ...@@ -532,6 +544,7 @@ typedef enum
DCH_MM, DCH_MM,
DCH_MONTH, DCH_MONTH,
DCH_MON, DCH_MON,
DCH_MS,
DCH_Month, DCH_Month,
DCH_Mon, DCH_Mon,
DCH_P_M, DCH_P_M,
...@@ -541,6 +554,7 @@ typedef enum ...@@ -541,6 +554,7 @@ typedef enum
DCH_SSSS, DCH_SSSS,
DCH_SS, DCH_SS,
DCH_TZ, DCH_TZ,
DCH_US,
DCH_WW, DCH_WW,
DCH_W, DCH_W,
DCH_Y_YYY, DCH_Y_YYY,
...@@ -570,6 +584,7 @@ typedef enum ...@@ -570,6 +584,7 @@ typedef enum
DCH_mm, DCH_mm,
DCH_month, DCH_month,
DCH_mon, DCH_mon,
DCH_ms,
DCH_p_m, DCH_p_m,
DCH_pm, DCH_pm,
DCH_q, DCH_q,
...@@ -577,6 +592,7 @@ typedef enum ...@@ -577,6 +592,7 @@ typedef enum
DCH_ssss, DCH_ssss,
DCH_ss, DCH_ss,
DCH_tz, DCH_tz,
DCH_us,
DCH_ww, DCH_ww,
DCH_w, DCH_w,
DCH_y_yyy, DCH_y_yyy,
...@@ -662,6 +678,7 @@ static KeyWord DCH_keywords[] = { ...@@ -662,6 +678,7 @@ static KeyWord DCH_keywords[] = {
{"MM", 2, dch_date, DCH_MM, TRUE}, {"MM", 2, dch_date, DCH_MM, TRUE},
{"MONTH", 5, dch_date, DCH_MONTH, FALSE}, {"MONTH", 5, dch_date, DCH_MONTH, FALSE},
{"MON", 3, dch_date, DCH_MON, FALSE}, {"MON", 3, dch_date, DCH_MON, FALSE},
{"MS", 2, dch_time, DCH_MS, TRUE},
{"Month", 5, dch_date, DCH_Month, FALSE}, {"Month", 5, dch_date, DCH_Month, FALSE},
{"Mon", 3, dch_date, DCH_Mon, FALSE}, {"Mon", 3, dch_date, DCH_Mon, FALSE},
{"P.M.", 4, dch_time, DCH_P_M, FALSE}, /* P */ {"P.M.", 4, dch_time, DCH_P_M, FALSE}, /* P */
...@@ -671,6 +688,7 @@ static KeyWord DCH_keywords[] = { ...@@ -671,6 +688,7 @@ static KeyWord DCH_keywords[] = {
{"SSSS", 4, dch_time, DCH_SSSS, TRUE}, /* S */ {"SSSS", 4, dch_time, DCH_SSSS, TRUE}, /* S */
{"SS", 2, dch_time, DCH_SS, TRUE}, {"SS", 2, dch_time, DCH_SS, TRUE},
{"TZ", 2, dch_time, DCH_TZ, FALSE}, /* T */ {"TZ", 2, dch_time, DCH_TZ, FALSE}, /* T */
{"US", 2, dch_time, DCH_US, TRUE}, /* U */
{"WW", 2, dch_date, DCH_WW, TRUE}, /* W */ {"WW", 2, dch_date, DCH_WW, TRUE}, /* W */
{"W", 1, dch_date, DCH_W, TRUE}, {"W", 1, dch_date, DCH_W, TRUE},
{"Y,YYY", 5, dch_date, DCH_Y_YYY, TRUE}, /* Y */ {"Y,YYY", 5, dch_date, DCH_Y_YYY, TRUE}, /* Y */
...@@ -700,6 +718,7 @@ static KeyWord DCH_keywords[] = { ...@@ -700,6 +718,7 @@ static KeyWord DCH_keywords[] = {
{"mm", 2, dch_date, DCH_MM, TRUE}, {"mm", 2, dch_date, DCH_MM, TRUE},
{"month", 5, dch_date, DCH_month, FALSE}, {"month", 5, dch_date, DCH_month, FALSE},
{"mon", 3, dch_date, DCH_mon, FALSE}, {"mon", 3, dch_date, DCH_mon, FALSE},
{"ms", 2, dch_time, DCH_MS, TRUE},
{"p.m.", 4, dch_time, DCH_p_m, FALSE}, /* p */ {"p.m.", 4, dch_time, DCH_p_m, FALSE}, /* p */
{"pm", 2, dch_time, DCH_pm, FALSE}, {"pm", 2, dch_time, DCH_pm, FALSE},
{"q", 1, dch_date, DCH_Q, TRUE}, /* q */ {"q", 1, dch_date, DCH_Q, TRUE}, /* q */
...@@ -707,6 +726,7 @@ static KeyWord DCH_keywords[] = { ...@@ -707,6 +726,7 @@ static KeyWord DCH_keywords[] = {
{"ssss", 4, dch_time, DCH_SSSS, TRUE}, /* s */ {"ssss", 4, dch_time, DCH_SSSS, TRUE}, /* s */
{"ss", 2, dch_time, DCH_SS, TRUE}, {"ss", 2, dch_time, DCH_SS, TRUE},
{"tz", 2, dch_time, DCH_tz, FALSE}, /* t */ {"tz", 2, dch_time, DCH_tz, FALSE}, /* t */
{"us", 2, dch_time, DCH_US, TRUE}, /* u */
{"ww", 2, dch_date, DCH_WW, TRUE}, /* w */ {"ww", 2, dch_date, DCH_WW, TRUE}, /* w */
{"w", 1, dch_date, DCH_W, TRUE}, {"w", 1, dch_date, DCH_W, TRUE},
{"y,yyy", 5, dch_date, DCH_Y_YYY, TRUE}, /* y */ {"y,yyy", 5, dch_date, DCH_Y_YYY, TRUE}, /* y */
...@@ -779,10 +799,10 @@ static int DCH_index[KeyWord_INDEX_SIZE] = { ...@@ -779,10 +799,10 @@ static int DCH_index[KeyWord_INDEX_SIZE] = {
-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, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1, -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
DCH_FX, -1, DCH_HH24, DCH_IW, DCH_J, -1, -1, DCH_MI, -1, -1, DCH_FX, -1, DCH_HH24, DCH_IW, DCH_J, -1, -1, DCH_MI, -1, -1,
DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, -1, -1, DCH_WW, -1, DCH_Y_YYY, DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
-1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc, -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iw, DCH_j, -1, -1, DCH_mi, DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iw, DCH_j, -1, -1, DCH_mi,
-1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, -1, -1, DCH_ww, -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
-1, DCH_y_yyy, -1, -1, -1, -1 -1, DCH_y_yyy, -1, -1, -1, -1
/*---- chars over 126 are skiped ----*/ /*---- chars over 126 are skiped ----*/
...@@ -857,7 +877,7 @@ static KeySuffix *suff_search(char *str, KeySuffix *suf, int type); ...@@ -857,7 +877,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_processor(FormatNode *node, char *inout, int flag); static char *DCH_processor(FormatNode *node, char *inout, int flag, void *data);
#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);
...@@ -867,15 +887,15 @@ static void dump_node(FormatNode *node, int max); ...@@ -867,15 +887,15 @@ static void dump_node(FormatNode *node, int max);
static char *get_th(char *num, int type); static char *get_th(char *num, int type);
static char *str_numth(char *dest, char *num, int type); static char *str_numth(char *dest, char *num, int type);
static int int4len(int4 num); static int strdigits_len(char *str);
static char *str_toupper(char *buff); static char *str_toupper(char *buff);
static char *str_tolower(char *buff); static char *str_tolower(char *buff);
/* static int is_acdc(char *str, int *len); */ /* static int is_acdc(char *str, int *len); */
static int seq_search(char *name, char **array, int type, int max, int *len); static int seq_search(char *name, char **array, int type, int max, int *len);
static int dch_global(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_global(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
static int dch_time(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
static int dch_date(int arg, char *inout, int suf, int flag, FormatNode *node); static int dch_date(int arg, char *inout, int suf, int flag, FormatNode *node, void *data);
static char *fill_str(char *str, int c, int max); static char *fill_str(char *str, int c, int max);
static FormatNode *NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag); static FormatNode *NUM_cache(int len, NUMDesc *Num, char *pars_str, int *flag);
static char *int_to_roman(int number); static char *int_to_roman(int number);
...@@ -1249,7 +1269,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw, ...@@ -1249,7 +1269,7 @@ parse_format(FormatNode *node, char *str, KeyWord *kw,
* ---------- * ----------
*/ */
static char * static char *
DCH_processor(FormatNode *node, char *inout, int flag) DCH_processor(FormatNode *node, char *inout, int flag, void *data)
{ {
FormatNode *n; FormatNode *n;
char *s; char *s;
...@@ -1269,7 +1289,7 @@ DCH_processor(FormatNode *node, char *inout, int flag) ...@@ -1269,7 +1289,7 @@ DCH_processor(FormatNode *node, char *inout, int flag)
/* /*
* Call node action function * Call node action function
*/ */
len = n->key->action(n->key->id, s, n->suffix, flag, n); len = n->key->action(n->key->id, s, n->suffix, flag, n, data);
if (len > 0) if (len > 0)
s += len; s += len;
else if (len == -1) else if (len == -1)
...@@ -1344,7 +1364,7 @@ dump_node(FormatNode *node, int max) ...@@ -1344,7 +1364,7 @@ dump_node(FormatNode *node, int max)
} }
} }
#endif #endif /* DEBUG */
/***************************************************************************** /*****************************************************************************
* Private utils * Private utils
...@@ -1407,18 +1427,6 @@ str_numth(char *dest, char *num, int type) ...@@ -1407,18 +1427,6 @@ str_numth(char *dest, char *num, int type)
return dest; return dest;
} }
/* ----------
* Return length of integer writed in string
* ----------
*/
static int
int4len(int4 num)
{
char b[16];
return snprintf(b, sizeof(b), "%d", num);
}
/* ---------- /* ----------
* Convert string to upper-string * Convert string to upper-string
* ---------- * ----------
...@@ -1563,7 +1571,7 @@ dump_index(KeyWord *k, int *index) ...@@ -1563,7 +1571,7 @@ dump_index(KeyWord *k, int *index)
count, free_i); count, free_i);
} }
#endif #endif /* DEBUG */
/* ---------- /* ----------
* Skip TM / th in FROM_CHAR * Skip TM / th in FROM_CHAR
...@@ -1577,14 +1585,10 @@ dump_index(KeyWord *k, int *index) ...@@ -1577,14 +1585,10 @@ dump_index(KeyWord *k, int *index)
* ---------- * ----------
*/ */
static int static int
dch_global(int arg, char *inout, int suf, int flag, FormatNode *node) dch_global(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
{ {
switch (arg) if (arg == DCH_FX)
{ DCH_global_flag |= DCH_F_FX;
case DCH_FX:
DCH_global_flag |= DCH_F_FX;
break;
}
return -1; return -1;
} }
...@@ -1622,6 +1626,20 @@ is_next_separator(FormatNode *n) ...@@ -1622,6 +1626,20 @@ is_next_separator(FormatNode *n)
return TRUE; /* some non-digit input (separator) */ return TRUE; /* some non-digit input (separator) */
} }
static int
strdigits_len(char *str)
{
char *p = str;
int len = 0;
while (*p && isdigit((unsigned char ) *p) && len <= DCH_MAX_ITEM_SIZ)
{
len++;
p++;
}
return len;
}
#define AMPM_ERROR elog(ERROR, "to_timestamp(): bad AM/PM string") #define AMPM_ERROR elog(ERROR, "to_timestamp(): bad AM/PM string")
/* ---------- /* ----------
...@@ -1631,9 +1649,20 @@ is_next_separator(FormatNode *n) ...@@ -1631,9 +1649,20 @@ is_next_separator(FormatNode *n)
* ---------- * ----------
*/ */
static int static int
dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
{ {
char *p_inout = inout; char *p_inout = inout;
struct tm *tm = NULL;
TmFromChar *tmfc = NULL;
TmToChar *tmtc = NULL;
if (flag==TO_CHAR)
{
tmtc = (TmToChar *) data;
tm = tmtcTm(tmtc);
}
else
tmfc = (TmFromChar *) data;
switch (arg) switch (arg)
{ {
...@@ -1730,10 +1759,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1730,10 +1759,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->hh); sscanf(inout, "%d", &tmfc->hh);
return int4len((int4) tmfc->hh) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -1756,10 +1785,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1756,10 +1785,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->hh); sscanf(inout, "%d", &tmfc->hh);
return int4len((int4) tmfc->hh) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -1782,10 +1811,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1782,10 +1811,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->mi); sscanf(inout, "%d", &tmfc->mi);
return int4len((int4) tmfc->mi) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -1808,10 +1837,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1808,10 +1837,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->ss); sscanf(inout, "%d", &tmfc->ss);
return int4len((int4) tmfc->ss) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -1820,6 +1849,81 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1820,6 +1849,81 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
} }
break; break;
case DCH_MS: /* millisecond */
if (flag == TO_CHAR)
{
sprintf(inout, "%03d", (int) rint(tmtc->fsec * 1000));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return strlen(p_inout) - 1;
else
return 2;
}
else if (flag == FROM_CHAR)
{
int len, x;
if (is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ms);
len = x = strdigits_len(inout);
}
else
{
sscanf(inout, "%03d", &tmfc->ms);
x = strdigits_len(inout);
len = x = x > 3 ? 3 : x;
}
/* 25 is 0.25 and 250 is 0.25 too;
* 025 is 0.025 and not 0.25
*/
tmfc->ms *= x==1 ? 100 :
x==2 ? 10 : 1;
/* elog(NOTICE, "X: %d, MS: %d, LEN: %d", x, tmfc->ms, len); */
return len - 1 + SKIP_THth(suf);
}
break;
case DCH_US: /* microsecond */
if (flag == TO_CHAR)
{
sprintf(inout, "%06d", (int)rint(tmtc->fsec * 1000000));
if (S_THth(suf))
str_numth(p_inout, inout, S_TH_TYPE(suf));
if (S_THth(suf))
return strlen(p_inout) - 1;
else
return 5;
}
else if (flag == FROM_CHAR)
{
int len, x;
if (is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->us);
len = x = strdigits_len(inout);
}
else
{
sscanf(inout, "%06d", &tmfc->us);
x = strdigits_len(inout);
len = x = x > 6 ? 6 : x;
}
tmfc->us *= x==1 ? 100000 :
x==2 ? 10000 :
x==3 ? 1000 :
x==4 ? 100 :
x==5 ? 10 : 1;
/* elog(NOTICE, "X: %d, US: %d, LEN: %d", x, tmfc->us, len); */
return len - 1 + SKIP_THth(suf);
}
break;
case DCH_SSSS: case DCH_SSSS:
if (flag == TO_CHAR) if (flag == TO_CHAR)
{ {
...@@ -1832,26 +1936,31 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -1832,26 +1936,31 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (is_next_separator(node)) if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->ssss); sscanf(inout, "%d", &tmfc->ssss);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
}
else else
{
sscanf(inout, "%05d", &tmfc->ssss); sscanf(inout, "%05d", &tmfc->ssss);
return int4len((int4) tmfc->ssss) - 1 + SKIP_THth(suf); return 4 + SKIP_THth(suf);
}
} }
break; break;
case DCH_tz: case DCH_tz:
case DCH_TZ: case DCH_TZ:
if (flag == TO_CHAR && tzn) if (flag == TO_CHAR && tmtcTzn(tmtc))
{ {
int siz = strlen(tzn); int siz = strlen(tmtcTzn(tmtc));
if (arg == DCH_TZ) if (arg == DCH_TZ)
strcpy(inout, tzn); strcpy(inout, tmtcTzn(tmtc));
else else
{ {
char *p = palloc(siz); char *p = palloc(siz);
strcpy(p, tzn); strcpy(p, tmtcTzn(tmtc));
strcpy(inout, str_tolower(p)); strcpy(inout, str_tolower(p));
pfree(p); pfree(p);
} }
...@@ -1878,12 +1987,21 @@ do { \ ...@@ -1878,12 +1987,21 @@ do { \
* ---------- * ----------
*/ */
static int static int
dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) dch_date(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
{ {
char buff[DCH_CACHE_SIZE], char buff[DCH_CACHE_SIZE], *p_inout;
*p_inout; int i, len;
int i, struct tm *tm = NULL;
len; TmFromChar *tmfc = NULL;
TmToChar *tmtc = NULL;
if (flag==TO_CHAR)
{
tmtc = (TmToChar *) data;
tm = tmtcTm(tmtc);
}
else
tmfc = (TmFromChar *) data;
p_inout = inout; p_inout = inout;
...@@ -2042,10 +2160,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2042,10 +2160,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->mm); sscanf(inout, "%d", &tmfc->mm);
return int4len((int4) tmfc->mm) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -2105,10 +2223,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2105,10 +2223,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->ddd); sscanf(inout, "%d", &tmfc->ddd);
return int4len((int4) tmfc->ddd) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -2131,10 +2249,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2131,10 +2249,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->dd); sscanf(inout, "%d", &tmfc->dd);
return int4len((int4) tmfc->dd) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -2175,10 +2293,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2175,10 +2293,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->ww); sscanf(inout, "%d", &tmfc->ww);
return int4len((int4) tmfc->ww) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -2202,10 +2320,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2202,10 +2320,10 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (S_FM(suf)) if (S_FM(suf) || is_next_separator(node))
{ {
sscanf(inout, "%d", &tmfc->iw); sscanf(inout, "%d", &tmfc->iw);
return int4len((int4) tmfc->iw) - 1 + SKIP_THth(suf); return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
else else
{ {
...@@ -2247,8 +2365,16 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2247,8 +2365,16 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
sscanf(inout, "%d", &tmfc->cc); if (S_FM(suf) || is_next_separator(node))
return int4len((int4) tmfc->cc) + SKIP_THth(suf) - 1; {
sscanf(inout, "%d", &tmfc->cc);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
}
else
{
sscanf(inout, "%02d", &tmfc->cc);
return 1 + SKIP_THth(suf);
}
} }
break; break;
case DCH_Y_YYY: case DCH_Y_YYY:
...@@ -2267,12 +2393,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2267,12 +2393,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
sscanf(inout, "%d,%03d", &cc, &tmfc->yyyy); sscanf(inout, "%d,%03d", &cc, &tmfc->yyyy);
tmfc->yyyy += (cc * 1000); tmfc->yyyy += (cc * 1000);
if (!S_FM(suf) && tmfc->yyyy <= 9999 && tmfc->yyyy >= -9999) return strdigits_len(inout) + 3 + SKIP_THth(suf);
len = 5;
else
len = int4len((int4) tmfc->yyyy) + 1;
len += SKIP_THth(suf);
return len - 1;
} }
break; break;
case DCH_YYYY: case DCH_YYYY:
...@@ -2288,17 +2409,16 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2288,17 +2409,16 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
} }
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
if (is_next_separator(node)) if (S_FM(suf) || is_next_separator(node))
{
sscanf(inout, "%d", &tmfc->yyyy); sscanf(inout, "%d", &tmfc->yyyy);
return strdigits_len(inout) - 1 + SKIP_THth(suf);
}
else else
{
sscanf(inout, "%04d", &tmfc->yyyy); sscanf(inout, "%04d", &tmfc->yyyy);
return 3 + SKIP_THth(suf);
if (!S_FM(suf) && tmfc->yyyy <= 9999 && tmfc->yyyy >= -9999) }
len = 4;
else
len = int4len((int4) tmfc->yyyy);
len += SKIP_THth(suf);
return len - 1;
} }
break; break;
case DCH_YYY: case DCH_YYY:
...@@ -2431,7 +2551,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node) ...@@ -2431,7 +2551,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
else if (flag == FROM_CHAR) else if (flag == FROM_CHAR)
{ {
sscanf(inout, "%d", &tmfc->j); sscanf(inout, "%d", &tmfc->j);
return int4len((int4) tmfc->j) + SKIP_THth(suf) - 1; return strdigits_len(inout) - 1 + SKIP_THth(suf);
} }
break; break;
} }
...@@ -2523,80 +2643,41 @@ DCH_cache_search(char *str) ...@@ -2523,80 +2643,41 @@ DCH_cache_search(char *str)
return (DCHCacheEntry *) NULL; return (DCHCacheEntry *) NULL;
} }
static text *
/**************************************************************************** datetime_to_char_body(TmToChar *tmtc, text *fmt)
* Public routines
***************************************************************************/
/* -------------------
* TIMESTAMP to_char()
* -------------------
*/
Datum
timestamp_to_char(PG_FUNCTION_ARGS)
{ {
Timestamp dt = PG_GETARG_TIMESTAMP(0);
text *fmt = PG_GETARG_TEXT_P(1);
text *result,
*result_tmp;
FormatNode *format; FormatNode *format;
char *str; struct tm *tm = NULL;
double fsec; char *str_fmt, *result;
int len = 0, bool incache;
tz, int len = VARSIZE(fmt) - VARHDRSZ;
flag = 0,
x = 0;
len = VARSIZE(fmt) - VARHDRSZ;
if (len <= 0 || TIMESTAMP_NOT_FINITE(dt))
PG_RETURN_NULL();
ZERO_tm(tm);
tzn = NULL;
if (TIMESTAMP_IS_EPOCH(dt))
{
x = timestamp2tm(SetTimestamp(dt), NULL, tm, &fsec, NULL);
}
else if (TIMESTAMP_IS_CURRENT(dt))
{
x = timestamp2tm(SetTimestamp(dt), &tz, tm, &fsec, &tzn);
}
else
x = timestamp2tm(dt, &tz, tm, &fsec, &tzn);
if (x != 0)
elog(ERROR, "to_char(): Unable to convert timestamp to tm");
tm = tmtcTm(tmtc);
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;
tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1; tm->tm_yday = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(tm->tm_year, 1, 1) + 1;
/* /*
* Convert fmt to C string * Convert fmt to C string
*/ */
str = (char *) palloc(len + 1); str_fmt = (char *) palloc(len + 1);
memcpy(str, VARDATA(fmt), len); memcpy(str_fmt, VARDATA(fmt), len);
*(str + len) = '\0'; *(str_fmt + len) = '\0';
/* /*
* Allocate result * Allocate result
*/ */
result = (text *) palloc((len * DCH_MAX_ITEM_SIZ) + 1 + VARHDRSZ); result = palloc((len * DCH_MAX_ITEM_SIZ) + 1);
/* /*
* Allocate new memory if format picture is bigger than static cache * Allocate new memory if format picture is bigger than static cache
* and not use cache (call parser always) - flag=1 show this variant * and not use cache (call parser always) - incache=FALSE show this variant
*/ */
if (len > DCH_CACHE_SIZE) if (len > DCH_CACHE_SIZE)
{ {
format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
flag = 1; incache = FALSE;
parse_format(format, str, DCH_keywords, parse_format(format, str_fmt, DCH_keywords,
DCH_suff, DCH_index, DCH_TYPE, NULL); DCH_suff, DCH_index, DCH_TYPE, NULL);
(format + len)->type = NODE_TYPE_END; /* Paranoa? */ (format + len)->type = NODE_TYPE_END; /* Paranoa? */
...@@ -2609,19 +2690,18 @@ timestamp_to_char(PG_FUNCTION_ARGS) ...@@ -2609,19 +2690,18 @@ timestamp_to_char(PG_FUNCTION_ARGS)
* Use cache buffers * Use cache buffers
*/ */
DCHCacheEntry *ent; DCHCacheEntry *ent;
incache = TRUE;
flag = 0; if ((ent = DCH_cache_search(str_fmt)) == NULL)
if ((ent = DCH_cache_search(str)) == NULL)
{ {
ent = DCH_cache_getnew(str); ent = DCH_cache_getnew(str_fmt);
/* /*
* Not in the cache, must run parser and save a new * Not in the cache, must run parser and save a new
* format-picture to the cache. * format-picture to the cache.
*/ */
parse_format(ent->format, str, DCH_keywords, parse_format(ent->format, str_fmt, DCH_keywords,
DCH_suff, DCH_index, DCH_TYPE, NULL); DCH_suff, DCH_index, DCH_TYPE, NULL);
(ent->format + len)->type = NODE_TYPE_END; /* Paranoa? */ (ent->format + len)->type = NODE_TYPE_END; /* Paranoa? */
...@@ -2634,34 +2714,93 @@ timestamp_to_char(PG_FUNCTION_ARGS) ...@@ -2634,34 +2714,93 @@ timestamp_to_char(PG_FUNCTION_ARGS)
format = ent->format; format = ent->format;
} }
DCH_processor(format, VARDATA(result), TO_CHAR); DCH_processor(format, result, TO_CHAR, (void *) tmtc);
if (flag) if (!incache)
pfree(format); pfree(format);
pfree(str); pfree(str_fmt);
/* /*
* for result is allocated max memory, which current format-picture * for result is allocated max memory, which current format-picture
* needs, now it must be re-allocate to result real size * needs, now it allocate result with real size
*/ */
if (!(len = strlen(VARDATA(result)))) if (!(len = strlen(result)))
{
pfree(result); pfree(result);
PG_RETURN_NULL(); else
{
text *res = (text *) palloc(len + 1 + VARHDRSZ);
memcpy(VARDATA(res), result, len);
VARATT_SIZEP(res) = len + VARHDRSZ;
return res;
} }
return NULL;
}
result_tmp = result; /****************************************************************************
result = (text *) palloc(len + 1 + VARHDRSZ); * Public routines
***************************************************************************/
/* -------------------
* TIMESTAMP to_char()
* -------------------
*/
Datum
timestamp_to_char(PG_FUNCTION_ARGS)
{
Timestamp dt = PG_GETARG_TIMESTAMP(0);
text *fmt = PG_GETARG_TEXT_P(1), *res;
TmToChar tmtc;
int tz, r = 0;
strcpy(VARDATA(result), VARDATA(result_tmp)); if ((VARSIZE(fmt) - VARHDRSZ) <=0 || TIMESTAMP_NOT_FINITE(dt))
VARATT_SIZEP(result) = len + VARHDRSZ; PG_RETURN_NULL();
pfree(result_tmp);
PG_RETURN_TEXT_P(result); ZERO_tmtc(&tmtc);
if (TIMESTAMP_IS_EPOCH(dt))
r = timestamp2tm(SetTimestamp(dt), NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL);
else if (TIMESTAMP_IS_CURRENT(dt))
r = timestamp2tm(SetTimestamp(dt), &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc));
else
r = timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc));
if (r != 0)
elog(ERROR, "to_char(): Unable to convert timestamp to tm");
if (!(res=datetime_to_char_body(&tmtc, fmt)))
PG_RETURN_NULL();
PG_RETURN_TEXT_P(res);
} }
/* -------------------
* INTERVAL to_char()
* -------------------
*/
Datum
interval_to_char(PG_FUNCTION_ARGS)
{
Interval *it = PG_GETARG_INTERVAL_P(0);
text *fmt = PG_GETARG_TEXT_P(1), *res;
TmToChar tmtc;
if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
PG_RETURN_NULL();
ZERO_tmtc(&tmtc);
if (interval2tm(*it, tmtcTm(&tmtc), &tmtcFsec(&tmtc)) != 0)
PG_RETURN_NULL();
if (!(res=datetime_to_char_body(&tmtc, fmt)))
PG_RETURN_NULL();
PG_RETURN_TEXT_P(res);
}
/* --------------------- /* ---------------------
* TO_TIMESTAMP() * TO_TIMESTAMP()
* *
...@@ -2672,42 +2811,40 @@ timestamp_to_char(PG_FUNCTION_ARGS) ...@@ -2672,42 +2811,40 @@ timestamp_to_char(PG_FUNCTION_ARGS)
Datum Datum
to_timestamp(PG_FUNCTION_ARGS) to_timestamp(PG_FUNCTION_ARGS)
{ {
text *date_txt = PG_GETARG_TEXT_P(0); text *date_txt = PG_GETARG_TEXT_P(0);
text *fmt = PG_GETARG_TEXT_P(1); text *fmt = PG_GETARG_TEXT_P(1);
Timestamp result;
FormatNode *format; FormatNode *format;
int flag = 0; TmFromChar tmfc;
Timestamp result;
char *str; bool incache;
char *date_str; char *str;
int len, char *date_str;
date_len, int len, date_len, tz = 0;
fsec = 0, struct tm tm;
tz = 0; double fsec = 0;
ZERO_tm(tm); ZERO_tm(&tm);
ZERO_tmfc(tmfc); ZERO_tmfc(&tmfc);
len = VARSIZE(fmt) - VARHDRSZ; len = VARSIZE(fmt) - VARHDRSZ;
if (len) if (len)
{ {
/*
* Convert fmt to C string
*/
str = (char *) palloc(len + 1); str = (char *) palloc(len + 1);
memcpy(str, VARDATA(fmt), len); memcpy(str, VARDATA(fmt), len);
*(str + len) = '\0'; *(str + len) = '\0';
/* /*
* Allocate new memory if format picture is bigger than static * Allocate new memory if format picture is bigger than static
* cache and not use cache (call parser always) - flag=1 show this * cache and not use cache (call parser always) - incache=FALSE
* variant * show this variant
*/ */
if (len > DCH_CACHE_SIZE) if (len > DCH_CACHE_SIZE)
{ {
format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
flag = 1; incache = FALSE;
parse_format(format, str, DCH_keywords, parse_format(format, str, DCH_keywords,
DCH_suff, DCH_index, DCH_TYPE, NULL); DCH_suff, DCH_index, DCH_TYPE, NULL);
...@@ -2721,8 +2858,7 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2721,8 +2858,7 @@ to_timestamp(PG_FUNCTION_ARGS)
* Use cache buffers * Use cache buffers
*/ */
DCHCacheEntry *ent; DCHCacheEntry *ent;
incache = 0;
flag = 0;
if ((ent = DCH_cache_search(str)) == NULL) if ((ent = DCH_cache_search(str)) == NULL)
{ {
...@@ -2760,92 +2896,91 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2760,92 +2896,91 @@ to_timestamp(PG_FUNCTION_ARGS)
memcpy(date_str, VARDATA(date_txt), date_len); memcpy(date_str, VARDATA(date_txt), date_len);
*(date_str + date_len) = '\0'; *(date_str + date_len) = '\0';
DCH_processor(format, date_str, FROM_CHAR); DCH_processor(format, date_str, FROM_CHAR, (void *) &tmfc);
pfree(date_str); pfree(date_str);
pfree(str); pfree(str);
if (flag) if (incache)
pfree(format); pfree(format);
} }
DEBUG_TMFC(&tmfc);
/* /*
* Convert values that user define for FROM_CHAR * Convert values that user define for FROM_CHAR
* (to_date/to_timestamp) to standard 'tm' * (to_date/to_timestamp) to standard 'tm'
*/ */
#ifdef DEBUG_TO_FROM_CHAR if (tmfc.ssss)
NOTICE_TMFC;
#endif
if (tmfc->ssss)
{ {
int x = tmfc->ssss; int x = tmfc.ssss;
tm->tm_hour = x / 3600; tm.tm_hour = x / 3600;
x %= 3600; x %= 3600;
tm->tm_min = x / 60; tm.tm_min = x / 60;
x %= 60; x %= 60;
tm->tm_sec = x; tm.tm_sec = x;
} }
if (tmfc->cc) if (tmfc.cc)
tm->tm_year = (tmfc->cc - 1) * 100; tm.tm_year = (tmfc.cc - 1) * 100;
if (tmfc->ww) if (tmfc.ww)
tmfc->ddd = (tmfc->ww - 1) * 7 + 1; tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
if (tmfc->w) if (tmfc.w)
tmfc->dd = (tmfc->w - 1) * 7 + 1; tmfc.dd = (tmfc.w - 1) * 7 + 1;
if (tmfc->ss) if (tmfc.ss)
tm->tm_sec = tmfc->ss; tm.tm_sec = tmfc.ss;
if (tmfc->mi) if (tmfc.mi)
tm->tm_min = tmfc->mi; tm.tm_min = tmfc.mi;
if (tmfc->hh) if (tmfc.hh)
tm->tm_hour = tmfc->hh; tm.tm_hour = tmfc.hh;
if (tmfc->pm || tmfc->am) if (tmfc.pm || tmfc.am)
{ {
if (tm->tm_hour < 1 || tm->tm_hour > 12) if (tm.tm_hour < 1 || tm.tm_hour > 12)
elog(ERROR, "to_timestamp(): AM/PM hour must be between 1 and 12"); elog(ERROR, "to_timestamp(): AM/PM hour must be between 1 and 12");
if (tmfc->pm && tm->tm_hour < 12) if (tmfc.pm && tm.tm_hour < 12)
tm->tm_hour += 12; tm.tm_hour += 12;
else if (tmfc->am && tm->tm_hour == 12) else if (tmfc.am && tm.tm_hour == 12)
tm->tm_hour = 0; tm.tm_hour = 0;
} }
switch (tmfc->q) switch (tmfc.q)
{ {
case 1: case 1:
tm->tm_mday = 1; tm.tm_mday = 1;
tm->tm_mon = 1; tm.tm_mon = 1;
break; break;
case 2: case 2:
tm->tm_mday = 1; tm.tm_mday = 1;
tm->tm_mon = 4; tm.tm_mon = 4;
break; break;
case 3: case 3:
tm->tm_mday = 1; tm.tm_mday = 1;
tm->tm_mon = 7; tm.tm_mon = 7;
break; break;
case 4: case 4:
tm->tm_mday = 1; tm.tm_mday = 1;
tm->tm_mon = 10; tm.tm_mon = 10;
break; break;
} }
if (tmfc->yyyy) if (tmfc.yyyy)
tm->tm_year = tmfc->yyyy; tm.tm_year = tmfc.yyyy;
else if (tmfc->y) else if (tmfc.y)
{ {
/* /*
* 1-digit year: always +2000 * 1-digit year: always +2000
*/ */
tm->tm_year = tmfc->y + 2000; tm.tm_year = tmfc.y + 2000;
} }
else if (tmfc->yy) else if (tmfc.yy)
{ {
/*--------- /*---------
...@@ -2854,14 +2989,14 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2854,14 +2989,14 @@ to_timestamp(PG_FUNCTION_ARGS)
* '70' ... '99' = 1970 ... 1999 * '70' ... '99' = 1970 ... 1999
*--------- *---------
*/ */
tm->tm_year = tmfc->yy; tm.tm_year = tmfc.yy;
if (tm->tm_year < 70) if (tm.tm_year < 70)
tm->tm_year += 2000; tm.tm_year += 2000;
else else
tm->tm_year += 1900; tm.tm_year += 1900;
} }
else if (tmfc->yyy) else if (tmfc.yyy)
{ {
/*--------- /*---------
...@@ -2870,42 +3005,41 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2870,42 +3005,41 @@ to_timestamp(PG_FUNCTION_ARGS)
* '000' ... '099' = 2000 ... 2099 * '000' ... '099' = 2000 ... 2099
*--------- *---------
*/ */
tm->tm_year = tmfc->yyy; tm.tm_year = tmfc.yyy;
if (tm->tm_year >= 100) if (tm.tm_year >= 100)
tm->tm_year += 1000; tm.tm_year += 1000;
else else
tm->tm_year += 2000; tm.tm_year += 2000;
} }
if (tmfc.bc)
if (tmfc->bc)
{ {
if (tm->tm_year > 0) if (tm.tm_year > 0)
tm->tm_year = -(tm->tm_year - 1); tm.tm_year = -(tm.tm_year - 1);
else else
elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm->tm_year); elog(ERROR, "Inconsistant use of year %04d and 'BC'", tm.tm_year);
} }
if (tmfc->j) if (tmfc.j)
j2date(tmfc->j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(tmfc.j, &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
if (tmfc->iw) if (tmfc.iw)
isoweek2date(tmfc->iw, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); isoweek2date(tmfc.iw, &tm.tm_year, &tm.tm_mon, &tm.tm_mday);
if (tmfc->d) if (tmfc.d)
tm->tm_wday = tmfc->d; tm.tm_wday = tmfc.d;
if (tmfc->dd) if (tmfc.dd)
tm->tm_mday = tmfc->dd; tm.tm_mday = tmfc.dd;
if (tmfc->ddd) if (tmfc.ddd)
tm->tm_yday = tmfc->ddd; tm.tm_yday = tmfc.ddd;
if (tmfc->mm) if (tmfc.mm)
tm->tm_mon = tmfc->mm; tm.tm_mon = tmfc.mm;
/* /*
* we not ignore DDD * we don't ignore DDD
*/ */
if (tmfc->ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1)) if (tmfc.ddd && (tm.tm_mon <= 1 || tm.tm_mday <= 1))
{ {
/* count mday and mon from yday */ /* count mday and mon from yday */
int *y, int *y,
...@@ -2915,34 +3049,35 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2915,34 +3049,35 @@ to_timestamp(PG_FUNCTION_ARGS)
{31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0}, {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0},
{31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}}; {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}};
if (!tm->tm_year) if (!tm.tm_year)
elog(ERROR, "to_timestamp() cat't convert yday without year information"); elog(ERROR, "to_timestamp() cat't convert yday without year information");
y = ysum[isleap(tm->tm_year)]; y = ysum[isleap(tm.tm_year)];
for (i = 0; i <= 11; i++) for (i = 0; i <= 11; i++)
{ {
if (tm->tm_yday < y[i]) if (tm.tm_yday < y[i])
break; break;
} }
if (tm->tm_mon <= 1) if (tm.tm_mon <= 1)
tm->tm_mon = i + 1; tm.tm_mon = i + 1;
if (tm->tm_mday <= 1) if (tm.tm_mday <= 1)
tm->tm_mday = i == 0 ? tm->tm_yday : tm.tm_mday = i == 0 ? tm.tm_yday :
tm->tm_yday - y[i - 1]; tm.tm_yday - y[i - 1];
} }
if (tmfc.ms)
fsec += (double) tmfc.ms / 1000;
if (tmfc.us)
fsec += (double) tmfc.us / 1000000;
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
#ifdef DEBUG_TO_FROM_CHAR DEBUG_TM(&tm);
NOTICE_TM; tz = DetermineLocalTimeZone(&tm);
#endif
tz = DetermineLocalTimeZone(tm); if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
#ifdef DEBUG_TO_FROM_CHAR
NOTICE_TM;
#endif
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
elog(ERROR, "to_timestamp(): can't convert 'tm' to timestamp."); elog(ERROR, "to_timestamp(): can't convert 'tm' to timestamp.");
PG_RETURN_TIMESTAMP(result); PG_RETURN_TIMESTAMP(result);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.49 2001/05/03 22:53:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.50 2001/09/06 03:22:42 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,9 +33,6 @@ static double time2t(const int hour, const int min, const double sec); ...@@ -33,9 +33,6 @@ static double time2t(const int hour, const int min, const double sec);
static int EncodeSpecialTimestamp(Timestamp dt, char *str); static int EncodeSpecialTimestamp(Timestamp dt, char *str);
static Timestamp dt2local(Timestamp dt, int timezone); static Timestamp dt2local(Timestamp dt, int timezone);
static void dt2time(Timestamp dt, int *hour, int *min, double *sec); static void dt2time(Timestamp dt, int *hour, int *min, double *sec);
static int interval2tm(Interval span, struct tm * tm, float8 *fsec);
static int tm2interval(struct tm * tm, double fsec, Interval *span);
/***************************************************************************** /*****************************************************************************
* USER I/O ROUTINES * * USER I/O ROUTINES *
...@@ -412,7 +409,7 @@ tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result) ...@@ -412,7 +409,7 @@ tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result)
/* interval2tm() /* interval2tm()
* Convert a interval data type to a tm structure. * Convert a interval data type to a tm structure.
*/ */
static int int
interval2tm(Interval span, struct tm * tm, float8 *fsec) interval2tm(Interval span, struct tm * tm, float8 *fsec)
{ {
double time; double time;
...@@ -444,7 +441,7 @@ interval2tm(Interval span, struct tm * tm, float8 *fsec) ...@@ -444,7 +441,7 @@ interval2tm(Interval span, struct tm * tm, float8 *fsec)
return 0; return 0;
} /* interval2tm() */ } /* interval2tm() */
static int int
tm2interval(struct tm * tm, double fsec, Interval *span) tm2interval(struct tm * tm, double fsec, Interval *span)
{ {
span->month = ((tm->tm_year * 12) + tm->tm_mon); span->month = ((tm->tm_year * 12) + tm->tm_mon);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.207 2001/08/26 16:56:02 tgl Exp $ * $Id: pg_proc.h,v 1.208 2001/09/06 03:22:42 momjian Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2476,10 +2476,12 @@ DATA(insert OID = 1776 ( to_char PGUID 12 f t f t 2 f 25 "701 25" 100 0 0 100 ...@@ -2476,10 +2476,12 @@ DATA(insert OID = 1776 ( to_char PGUID 12 f t f t 2 f 25 "701 25" 100 0 0 100
DESCR("format float8 to text"); DESCR("format float8 to text");
DATA(insert OID = 1777 ( to_number PGUID 12 f t f t 2 f 1700 "25 25" 100 0 0 100 numeric_to_number - )); DATA(insert OID = 1777 ( to_number PGUID 12 f t f t 2 f 1700 "25 25" 100 0 0 100 numeric_to_number - ));
DESCR("convert text to numeric"); DESCR("convert text to numeric");
DATA(insert OID = 1778 ( to_timestamp PGUID 12 f t f t 2 f 1184 "25 25" 100 0 0 100 to_timestamp - )); DATA(insert OID = 1778 ( to_timestamp PGUID 12 f t f t 2 f 1184 "25 25" 100 0 0 100 to_timestamp - ));
DESCR("convert text to timestamp"); DESCR("convert text to timestamp");
DATA(insert OID = 1780 ( to_date PGUID 12 f t f t 2 f 1082 "25 25" 100 0 0 100 to_date - )); DATA(insert OID = 1780 ( to_date PGUID 12 f t f t 2 f 1082 "25 25" 100 0 0 100 to_date - ));
DESCR("convert text to date"); DESCR("convert text to date");
DATA(insert OID = 1768 ( to_char PGUID 12 f t f t 2 f 25 "1186 25" 100 0 0 100 interval_to_char - ));
DESCR("format interval to text");
DATA(insert OID = 1282 ( quote_ident PGUID 12 f t t t 1 f 25 "25" 100 0 0 100 quote_ident - )); DATA(insert OID = 1282 ( quote_ident PGUID 12 f t t t 1 f 25 "25" 100 0 0 100 quote_ident - ));
DESCR("quote an identifier for usage in a querystring"); DESCR("quote an identifier for usage in a querystring");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.h * formatting.h
* *
* $Id: formatting.h,v 1.7 2001/01/24 19:43:28 momjian Exp $ * $Id: formatting.h,v 1.8 2001/09/06 03:22:42 momjian Exp $
* *
* *
* Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group * Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* 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.
* *
* Karel Zak - Zakkr * Karel Zak
* *
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
*/ */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
extern Datum timestamp_to_char(PG_FUNCTION_ARGS); extern Datum timestamp_to_char(PG_FUNCTION_ARGS);
extern Datum interval_to_char(PG_FUNCTION_ARGS);
extern Datum to_timestamp(PG_FUNCTION_ARGS); extern Datum to_timestamp(PG_FUNCTION_ARGS);
extern Datum to_date(PG_FUNCTION_ARGS); extern Datum to_date(PG_FUNCTION_ARGS);
extern Datum numeric_to_number(PG_FUNCTION_ARGS); extern Datum numeric_to_number(PG_FUNCTION_ARGS);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: timestamp.h,v 1.16 2001/03/22 04:01:14 momjian Exp $ * $Id: timestamp.h,v 1.17 2001/09/06 03:22:42 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -177,6 +177,9 @@ extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt); ...@@ -177,6 +177,9 @@ extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm,
double *fsec, char **tzn); double *fsec, char **tzn);
extern int interval2tm(Interval span, struct tm * tm, float8 *fsec);
extern int tm2interval(struct tm * tm, double fsec, Interval *span);
extern Timestamp SetTimestamp(Timestamp timestamp); extern Timestamp SetTimestamp(Timestamp timestamp);
extern void isoweek2date(int woy, int *year, int *mon, int *mday); extern void isoweek2date(int woy, int *year, int *mon, int *mday);
......
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