@ -86,6 +86,7 @@
# endif
# endif
# include "catalog/pg_collation.h"
# include "catalog/pg_collation.h"
# include "catalog/pg_type.h"
# include "mb/pg_wchar.h"
# include "mb/pg_wchar.h"
# include "utils/builtins.h"
# include "utils/builtins.h"
# include "utils/date.h"
# include "utils/date.h"
@ -434,7 +435,8 @@ typedef struct
clock , /* 12 or 24 hour clock? */
clock , /* 12 or 24 hour clock? */
tzsign , /* +1, -1 or 0 if timezone info is absent */
tzsign , /* +1, -1 or 0 if timezone info is absent */
tzh ,
tzh ,
tzm ;
tzm ,
ff ; /* fractional precision */
} TmFromChar ;
} TmFromChar ;
# define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
# define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
@ -594,6 +596,12 @@ typedef enum
DCH_Day ,
DCH_Day ,
DCH_Dy ,
DCH_Dy ,
DCH_D ,
DCH_D ,
DCH_FF1 ,
DCH_FF2 ,
DCH_FF3 ,
DCH_FF4 ,
DCH_FF5 ,
DCH_FF6 ,
DCH_FX , /* global suffix */
DCH_FX , /* global suffix */
DCH_HH24 ,
DCH_HH24 ,
DCH_HH12 ,
DCH_HH12 ,
@ -643,6 +651,12 @@ typedef enum
DCH_dd ,
DCH_dd ,
DCH_dy ,
DCH_dy ,
DCH_d ,
DCH_d ,
DCH_ff1 ,
DCH_ff2 ,
DCH_ff3 ,
DCH_ff4 ,
DCH_ff5 ,
DCH_ff6 ,
DCH_fx ,
DCH_fx ,
DCH_hh24 ,
DCH_hh24 ,
DCH_hh12 ,
DCH_hh12 ,
@ -743,7 +757,13 @@ static const KeyWord DCH_keywords[] = {
{ " Day " , 3 , DCH_Day , false , FROM_CHAR_DATE_NONE } ,
{ " Day " , 3 , DCH_Day , false , FROM_CHAR_DATE_NONE } ,
{ " Dy " , 2 , DCH_Dy , false , FROM_CHAR_DATE_NONE } ,
{ " Dy " , 2 , DCH_Dy , false , FROM_CHAR_DATE_NONE } ,
{ " D " , 1 , DCH_D , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " D " , 1 , DCH_D , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " FX " , 2 , DCH_FX , false , FROM_CHAR_DATE_NONE } , /* F */
{ " FF1 " , 3 , DCH_FF1 , false , FROM_CHAR_DATE_NONE } , /* F */
{ " FF2 " , 3 , DCH_FF2 , false , FROM_CHAR_DATE_NONE } ,
{ " FF3 " , 3 , DCH_FF3 , false , FROM_CHAR_DATE_NONE } ,
{ " FF4 " , 3 , DCH_FF4 , false , FROM_CHAR_DATE_NONE } ,
{ " FF5 " , 3 , DCH_FF5 , false , FROM_CHAR_DATE_NONE } ,
{ " FF6 " , 3 , DCH_FF6 , false , FROM_CHAR_DATE_NONE } ,
{ " FX " , 2 , DCH_FX , false , FROM_CHAR_DATE_NONE } ,
{ " HH24 " , 4 , DCH_HH24 , true , FROM_CHAR_DATE_NONE } , /* H */
{ " HH24 " , 4 , DCH_HH24 , true , FROM_CHAR_DATE_NONE } , /* H */
{ " HH12 " , 4 , DCH_HH12 , true , FROM_CHAR_DATE_NONE } ,
{ " HH12 " , 4 , DCH_HH12 , true , FROM_CHAR_DATE_NONE } ,
{ " HH " , 2 , DCH_HH , true , FROM_CHAR_DATE_NONE } ,
{ " HH " , 2 , DCH_HH , true , FROM_CHAR_DATE_NONE } ,
@ -792,7 +812,13 @@ static const KeyWord DCH_keywords[] = {
{ " dd " , 2 , DCH_DD , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " dd " , 2 , DCH_DD , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " dy " , 2 , DCH_dy , false , FROM_CHAR_DATE_NONE } ,
{ " dy " , 2 , DCH_dy , false , FROM_CHAR_DATE_NONE } ,
{ " d " , 1 , DCH_D , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " d " , 1 , DCH_D , true , FROM_CHAR_DATE_GREGORIAN } ,
{ " fx " , 2 , DCH_FX , false , FROM_CHAR_DATE_NONE } , /* f */
{ " ff1 " , 3 , DCH_FF1 , false , FROM_CHAR_DATE_NONE } , /* f */
{ " ff2 " , 3 , DCH_FF2 , false , FROM_CHAR_DATE_NONE } ,
{ " ff3 " , 3 , DCH_FF3 , false , FROM_CHAR_DATE_NONE } ,
{ " ff4 " , 3 , DCH_FF4 , false , FROM_CHAR_DATE_NONE } ,
{ " ff5 " , 3 , DCH_FF5 , false , FROM_CHAR_DATE_NONE } ,
{ " ff6 " , 3 , DCH_FF6 , false , FROM_CHAR_DATE_NONE } ,
{ " fx " , 2 , DCH_FX , false , FROM_CHAR_DATE_NONE } ,
{ " hh24 " , 4 , DCH_HH24 , true , FROM_CHAR_DATE_NONE } , /* h */
{ " hh24 " , 4 , DCH_HH24 , true , FROM_CHAR_DATE_NONE } , /* h */
{ " hh12 " , 4 , DCH_HH12 , true , FROM_CHAR_DATE_NONE } ,
{ " hh12 " , 4 , DCH_HH12 , true , FROM_CHAR_DATE_NONE } ,
{ " hh " , 2 , DCH_HH , true , FROM_CHAR_DATE_NONE } ,
{ " hh " , 2 , DCH_HH , true , FROM_CHAR_DATE_NONE } ,
@ -893,10 +919,10 @@ static const 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 , - 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_IDDD , DCH_J , - 1 , - 1 , DCH_MI , - 1 , DCH_OF ,
DCH_FF1 , - 1 , DCH_HH24 , DCH_IDDD , DCH_J , - 1 , - 1 , DCH_MI , - 1 , DCH_OF ,
DCH_P_M , DCH_Q , DCH_RM , DCH_SSSS , DCH_TZH , DCH_US , - 1 , DCH_WW , - 1 , DCH_Y_YYY ,
DCH_P_M , DCH_Q , DCH_RM , DCH_SSSS , DCH_TZH , 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_iddd , DCH_j , - 1 , - 1 , DCH_mi ,
DCH_day , - 1 , DCH_ff1 , - 1 , DCH_hh24 , DCH_iddd , DCH_j , - 1 , - 1 , DCH_mi ,
- 1 , - 1 , DCH_p_m , DCH_q , DCH_rm , DCH_ssss , DCH_tz , DCH_us , - 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
@ -960,7 +986,6 @@ typedef struct NUMProc
* L_currency_symbol ;
* L_currency_symbol ;
} NUMProc ;
} NUMProc ;
/* ----------
/* ----------
* Functions
* Functions
* - - - - - - - - - -
* - - - - - - - - - -
@ -993,7 +1018,7 @@ static int from_char_parse_int(int *dest, char **src, FormatNode *node);
static int seq_search ( char * name , const char * const * array , int type , int max , int * len ) ;
static int seq_search ( char * name , const char * const * array , int type , int max , int * len ) ;
static int from_char_seq_search ( int * dest , char * * src , const char * const * array , int type , int max , FormatNode * node ) ;
static int from_char_seq_search ( int * dest , char * * src , const char * const * array , int type , int max , FormatNode * node ) ;
static void do_to_timestamp ( text * date_txt , text * fmt ,
static void do_to_timestamp ( text * date_txt , text * fmt ,
struct pg_tm * tm , fsec_t * fsec ) ;
struct pg_tm * tm , fsec_t * fsec , int * fprec ) ;
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 , text * pars_str , bool * shouldFree ) ;
static FormatNode * NUM_cache ( int len , NUMDesc * Num , text * pars_str , bool * shouldFree ) ;
static char * int_to_roman ( int number ) ;
static char * int_to_roman ( int number ) ;
@ -2518,18 +2543,32 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
str_numth ( s , s , S_TH_TYPE ( n - > suffix ) ) ;
str_numth ( s , s , S_TH_TYPE ( n - > suffix ) ) ;
s + = strlen ( s ) ;
s + = strlen ( s ) ;
break ;
break ;
case DCH_MS : /* millisecond */
# define DCH_to_char_fsec(frac_fmt, frac_val) \
sprintf ( s , " %03d " , ( int ) ( in - > fsec / INT64CONST ( 1000 ) ) ) ;
sprintf ( s , frac_fmt , ( int ) ( frac_val ) ) ; \
if ( S_THth ( n - > suffix ) )
if ( S_THth ( n - > suffix ) ) \
str_numth ( s , s , S_TH_TYPE ( n - > suffix ) ) ;
str_numth ( s , s , S_TH_TYPE ( n - > suffix ) ) ; \
s + = strlen ( s ) ;
s + = strlen ( s ) ;
case DCH_FF1 : /* tenth of second */
DCH_to_char_fsec ( " %01d " , in - > fsec / 100000 ) ;
break ;
case DCH_FF2 : /* hundredth of second */
DCH_to_char_fsec ( " %02d " , in - > fsec / 10000 ) ;
break ;
case DCH_FF3 :
case DCH_MS : /* millisecond */
DCH_to_char_fsec ( " %03d " , in - > fsec / 1000 ) ;
break ;
break ;
case DCH_FF4 : /* tenth of a millisecond */
DCH_to_char_fsec ( " %04d " , in - > fsec / 100 ) ;
break ;
case DCH_FF5 : /* hundredth of a millisecond */
DCH_to_char_fsec ( " %05d " , in - > fsec / 10 ) ;
break ;
case DCH_FF6 :
case DCH_US : /* microsecond */
case DCH_US : /* microsecond */
sprintf ( s , " %06d " , ( int ) in - > fsec ) ;
DCH_to_char_fsec ( " %06d " , in - > fsec ) ;
if ( S_THth ( n - > suffix ) )
str_numth ( s , s , S_TH_TYPE ( n - > suffix ) ) ;
s + = strlen ( s ) ;
break ;
break ;
# undef DCH_to_char_fsec
case DCH_SSSS :
case DCH_SSSS :
sprintf ( s , " %d " , tm - > tm_hour * SECS_PER_HOUR +
sprintf ( s , " %d " , tm - > tm_hour * SECS_PER_HOUR +
tm - > tm_min * SECS_PER_MINUTE +
tm - > tm_min * SECS_PER_MINUTE +
@ -3154,8 +3193,18 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
SKIP_THth ( s , n - > suffix ) ;
SKIP_THth ( s , n - > suffix ) ;
break ;
break ;
case DCH_FF1 :
case DCH_FF2 :
case DCH_FF3 :
case DCH_FF4 :
case DCH_FF5 :
case DCH_FF6 :
out - > ff = n - > key - > id - DCH_FF1 + 1 ;
/* fall through */
case DCH_US : /* microsecond */
case DCH_US : /* microsecond */
len = from_char_parse_int_len ( & out - > us , & s , 6 , n ) ;
len = from_char_parse_int_len ( & out - > us , & s ,
n - > key - > id = = DCH_US ? 6 :
out - > ff , n ) ;
out - > us * = len = = 1 ? 100000 :
out - > us * = len = = 1 ? 100000 :
len = = 2 ? 10000 :
len = = 2 ? 10000 :
@ -3689,8 +3738,9 @@ to_timestamp(PG_FUNCTION_ARGS)
int tz ;
int tz ;
struct pg_tm tm ;
struct pg_tm tm ;
fsec_t fsec ;
fsec_t fsec ;
int fprec ;
do_to_timestamp ( date_txt , fmt , & tm , & fsec ) ;
do_to_timestamp ( date_txt , fmt , & tm , & fsec , & fprec ) ;
/* Use the specified time zone, if any. */
/* Use the specified time zone, if any. */
if ( tm . tm_zone )
if ( tm . tm_zone )
@ -3708,6 +3758,10 @@ to_timestamp(PG_FUNCTION_ARGS)
( errcode ( ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ) ,
( errcode ( ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ) ,
errmsg ( " timestamp out of range " ) ) ) ;
errmsg ( " timestamp out of range " ) ) ) ;
/* Use the specified fractional precision, if any. */
if ( fprec )
AdjustTimestampForTypmod ( & result , fprec ) ;
PG_RETURN_TIMESTAMP ( result ) ;
PG_RETURN_TIMESTAMP ( result ) ;
}
}
@ -3725,7 +3779,7 @@ to_date(PG_FUNCTION_ARGS)
struct pg_tm tm ;
struct pg_tm tm ;
fsec_t fsec ;
fsec_t fsec ;
do_to_timestamp ( date_txt , fmt , & tm , & fsec ) ;
do_to_timestamp ( date_txt , fmt , & tm , & fsec , NULL ) ;
/* Prevent overflow in Julian-day routines */
/* Prevent overflow in Julian-day routines */
if ( ! IS_VALID_JULIAN ( tm . tm_year , tm . tm_mon , tm . tm_mday ) )
if ( ! IS_VALID_JULIAN ( tm . tm_year , tm . tm_mon , tm . tm_mday ) )
@ -3749,8 +3803,8 @@ to_date(PG_FUNCTION_ARGS)
/*
/*
* do_to_timestamp : shared code for to_timestamp and to_date
* do_to_timestamp : shared code for to_timestamp and to_date
*
*
* Parse the ' date_txt ' according to ' fmt ' , return results as a struct pg_tm
* Parse the ' date_txt ' according to ' fmt ' , return results as a struct pg_tm ,
* and fractional seconds .
* fractional seconds , and fractional precision .
*
*
* We parse ' fmt ' into a list of FormatNodes , which is then passed to
* We parse ' fmt ' into a list of FormatNodes , which is then passed to
* DCH_from_char to populate a TmFromChar with the parsed contents of
* DCH_from_char to populate a TmFromChar with the parsed contents of
@ -3761,7 +3815,7 @@ to_date(PG_FUNCTION_ARGS)
*/
*/
static void
static void
do_to_timestamp ( text * date_txt , text * fmt ,
do_to_timestamp ( text * date_txt , text * fmt ,
struct pg_tm * tm , fsec_t * fsec )
struct pg_tm * tm , fsec_t * fsec , int * fprec )
{
{
FormatNode * format ;
FormatNode * format ;
TmFromChar tmfc ;
TmFromChar tmfc ;
@ -3817,6 +3871,7 @@ do_to_timestamp(text *date_txt, text *fmt,
DCH_from_char ( format , date_str , & tmfc ) ;
DCH_from_char ( format , date_str , & tmfc ) ;
pfree ( fmt_str ) ;
pfree ( fmt_str ) ;
if ( ! incache )
if ( ! incache )
pfree ( format ) ;
pfree ( format ) ;
}
}
@ -3998,6 +4053,8 @@ do_to_timestamp(text *date_txt, text *fmt,
* fsec + = tmfc . ms * 1000 ;
* fsec + = tmfc . ms * 1000 ;
if ( tmfc . us )
if ( tmfc . us )
* fsec + = tmfc . us ;
* fsec + = tmfc . us ;
if ( fprec )
* fprec = tmfc . ff ; /* fractional precision, if specified */
/* Range-check date fields according to bit mask computed above */
/* Range-check date fields according to bit mask computed above */
if ( fmask ! = 0 )
if ( fmask ! = 0 )