@ -3553,9 +3553,6 @@ to_date(PG_FUNCTION_ARGS)
*
*
* The TmFromChar is then analysed and converted into the final results in
* The TmFromChar is then analysed and converted into the final results in
* struct ' tm ' and ' fsec ' .
* struct ' tm ' and ' fsec ' .
*
* This function does very little error checking , e . g .
* to_timestamp ( ' 20096040 ' , ' YYYYMMDD ' ) works
*/
*/
static void
static void
do_to_timestamp ( text * date_txt , text * fmt ,
do_to_timestamp ( text * date_txt , text * fmt ,
@ -3564,30 +3561,35 @@ do_to_timestamp(text *date_txt, text *fmt,
FormatNode * format ;
FormatNode * format ;
TmFromChar tmfc ;
TmFromChar tmfc ;
int fmt_len ;
int fmt_len ;
char * date_str ;
int fmask ;
date_str = text_to_cstring ( date_txt ) ;
ZERO_tmfc ( & tmfc ) ;
ZERO_tmfc ( & tmfc ) ;
ZERO_tm ( tm ) ;
ZERO_tm ( tm ) ;
* fsec = 0 ;
* fsec = 0 ;
fmask = 0 ; /* bit mask for ValidateDate() */
fmt_len = VARSIZE_ANY_EXHDR ( fmt ) ;
fmt_len = VARSIZE_ANY_EXHDR ( fmt ) ;
if ( fmt_len )
if ( fmt_len )
{
{
char * fmt_str ;
char * fmt_str ;
char * date_str ;
bool incache ;
bool incache ;
fmt_str = text_to_cstring ( fmt ) ;
fmt_str = text_to_cstring ( fmt ) ;
/*
* Allocate new memory if format picture is bigger than static cache
* and not use cache ( call parser always )
*/
if ( fmt_len > DCH_CACHE_SIZE )
if ( fmt_len > DCH_CACHE_SIZE )
{
{
format = ( FormatNode * ) palloc ( ( fmt_len + 1 ) * sizeof ( FormatNode ) ) ;
/*
* Allocate new memory if format picture is bigger than static
* cache and not use cache ( call parser always )
*/
incache = FALSE ;
incache = FALSE ;
format = ( FormatNode * ) palloc ( ( fmt_len + 1 ) * sizeof ( FormatNode ) ) ;
parse_format ( format , fmt_str , DCH_keywords ,
parse_format ( format , fmt_str , DCH_keywords ,
DCH_suff , DCH_index , DCH_TYPE , NULL ) ;
DCH_suff , DCH_index , DCH_TYPE , NULL ) ;
@ -3604,33 +3606,27 @@ do_to_timestamp(text *date_txt, text *fmt,
if ( ( ent = DCH_cache_search ( fmt_str ) ) = = NULL )
if ( ( ent = DCH_cache_search ( fmt_str ) ) = = NULL )
{
{
ent = DCH_cache_getnew ( fmt_str ) ;
/*
/*
* 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 .
*/
*/
ent = DCH_cache_getnew ( fmt_str ) ;
parse_format ( ent - > format , fmt_str , DCH_keywords ,
parse_format ( ent - > format , fmt_str , DCH_keywords ,
DCH_suff , DCH_index , DCH_TYPE , NULL ) ;
DCH_suff , DCH_index , DCH_TYPE , NULL ) ;
( ent - > format + fmt_len ) - > type = NODE_TYPE_END ; /* Paranoia? */
( ent - > format + fmt_len ) - > type = NODE_TYPE_END ; /* Paranoia? */
# ifdef DEBUG_TO_FROM_CHAR
/* dump_node(ent->format, fmt_len); */
/* dump_index(DCH_keywords, DCH_index); */
# endif
}
}
format = ent - > format ;
format = ent - > format ;
}
}
# ifdef DEBUG_TO_FROM_CHAR
# ifdef DEBUG_TO_FROM_CHAR
/* dump_node(format, fmt_len); */
/* dump_node(format, fmt_len); */
/* dump_index(DCH_keywords, DCH_index); */
# endif
# endif
date_str = text_to_cstring ( date_txt ) ;
DCH_from_char ( format , date_str , & tmfc ) ;
DCH_from_char ( format , date_str , & tmfc ) ;
pfree ( date_str ) ;
pfree ( fmt_str ) ;
pfree ( fmt_str ) ;
if ( ! incache )
if ( ! incache )
pfree ( format ) ;
pfree ( format ) ;
@ -3639,8 +3635,7 @@ do_to_timestamp(text *date_txt, text *fmt,
DEBUG_TMFC ( & tmfc ) ;
DEBUG_TMFC ( & tmfc ) ;
/*
/*
* Convert values that user define for FROM_CHAR ( to_date / to_timestamp ) to
* Convert to_date / to_timestamp input fields to standard ' tm '
* standard ' tm '
*/
*/
if ( tmfc . ssss )
if ( tmfc . ssss )
{
{
@ -3696,19 +3691,23 @@ do_to_timestamp(text *date_txt, text *fmt,
tm - > tm_year = ( tmfc . cc + 1 ) * 100 - tm - > tm_year + 1 ;
tm - > tm_year = ( tmfc . cc + 1 ) * 100 - tm - > tm_year + 1 ;
}
}
else
else
{
/* find century year for dates ending in "00" */
/* find century year for dates ending in "00" */
tm - > tm_year = tmfc . cc * 100 + ( ( tmfc . cc > = 0 ) ? 0 : 1 ) ;
tm - > tm_year = tmfc . cc * 100 + ( ( tmfc . cc > = 0 ) ? 0 : 1 ) ;
}
}
}
else
else
/* If a 4-digit year is provided, we use that and ignore CC. */
{
{
/* If a 4-digit year is provided, we use that and ignore CC. */
tm - > tm_year = tmfc . year ;
tm - > tm_year = tmfc . year ;
if ( tmfc . bc & & tm - > tm_year > 0 )
if ( tmfc . bc & & tm - > tm_year > 0 )
tm - > tm_year = - ( tm - > tm_year - 1 ) ;
tm - > tm_year = - ( tm - > tm_year - 1 ) ;
}
}
fmask | = DTK_M ( YEAR ) ;
}
}
else if ( tmfc . cc ) /* use first year of century */
else if ( tmfc . cc )
{
{
/* use first year of century */
if ( tmfc . bc )
if ( tmfc . bc )
tmfc . cc = - tmfc . cc ;
tmfc . cc = - tmfc . cc ;
if ( tmfc . cc > = 0 )
if ( tmfc . cc > = 0 )
@ -3717,10 +3716,14 @@ do_to_timestamp(text *date_txt, text *fmt,
else
else
/* +1 because year == 599 is 600 BC */
/* +1 because year == 599 is 600 BC */
tm - > tm_year = tmfc . cc * 100 + 1 ;
tm - > tm_year = tmfc . cc * 100 + 1 ;
fmask | = DTK_M ( 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 ) ;
fmask | = DTK_DATE_M ;
}
if ( tmfc . ww )
if ( tmfc . ww )
{
{
@ -3734,6 +3737,7 @@ do_to_timestamp(text *date_txt, text *fmt,
isoweekdate2date ( tmfc . ww , tmfc . d , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
isoweekdate2date ( tmfc . ww , tmfc . d , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
else
else
isoweek2date ( tmfc . ww , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
isoweek2date ( tmfc . ww , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
fmask | = DTK_DATE_M ;
}
}
else
else
tmfc . ddd = ( tmfc . ww - 1 ) * 7 + 1 ;
tmfc . ddd = ( tmfc . ww - 1 ) * 7 + 1 ;
@ -3741,14 +3745,16 @@ do_to_timestamp(text *date_txt, text *fmt,
if ( tmfc . w )
if ( tmfc . w )
tmfc . dd = ( tmfc . w - 1 ) * 7 + 1 ;
tmfc . dd = ( tmfc . w - 1 ) * 7 + 1 ;
if ( tmfc . d )
tm - > tm_wday = tmfc . d - 1 ; /* convert to native numbering */
if ( tmfc . dd )
if ( tmfc . dd )
{
tm - > tm_mday = tmfc . dd ;
tm - > tm_mday = tmfc . dd ;
if ( tmfc . ddd )
fmask | = DTK_M ( DAY ) ;
tm - > tm_yday = tmfc . ddd ;
}
if ( tmfc . mm )
if ( tmfc . mm )
{
tm - > tm_mon = tmfc . mm ;
tm - > tm_mon = tmfc . mm ;
fmask | = DTK_M ( MONTH ) ;
}
if ( tmfc . ddd & & ( tm - > tm_mon < = 1 | | tm - > tm_mday < = 1 ) )
if ( tmfc . ddd & & ( tm - > tm_mon < = 1 | | tm - > tm_mday < = 1 ) )
{
{
@ -3771,6 +3777,7 @@ do_to_timestamp(text *date_txt, text *fmt,
j0 = isoweek2j ( tm - > tm_year , 1 ) - 1 ;
j0 = isoweek2j ( tm - > tm_year , 1 ) - 1 ;
j2date ( j0 + tmfc . ddd , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
j2date ( j0 + tmfc . ddd , & tm - > tm_year , & tm - > tm_mon , & tm - > tm_mday ) ;
fmask | = DTK_DATE_M ;
}
}
else
else
{
{
@ -3785,7 +3792,7 @@ do_to_timestamp(text *date_txt, text *fmt,
for ( i = 1 ; i < = MONTHS_PER_YEAR ; i + + )
for ( i = 1 ; i < = MONTHS_PER_YEAR ; i + + )
{
{
if ( tmfc . ddd < y [ i ] )
if ( tmfc . ddd < = y [ i ] )
break ;
break ;
}
}
if ( tm - > tm_mon < = 1 )
if ( tm - > tm_mon < = 1 )
@ -3793,6 +3800,8 @@ do_to_timestamp(text *date_txt, text *fmt,
if ( tm - > tm_mday < = 1 )
if ( tm - > tm_mday < = 1 )
tm - > tm_mday = tmfc . ddd - y [ i - 1 ] ;
tm - > tm_mday = tmfc . ddd - y [ i - 1 ] ;
fmask | = DTK_M ( MONTH ) | DTK_M ( DAY ) ;
}
}
}
}
@ -3808,7 +3817,38 @@ do_to_timestamp(text *date_txt, text *fmt,
* fsec + = ( double ) tmfc . us / 1000000 ;
* fsec + = ( double ) tmfc . us / 1000000 ;
# endif
# endif
/* Range-check date fields according to bit mask computed above */
if ( fmask ! = 0 )
{
/* We already dealt with AD/BC, so pass isjulian = true */
int dterr = ValidateDate ( fmask , true , false , false , tm ) ;
if ( dterr ! = 0 )
{
/*
* Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
* said DTERR_MD_FIELD_OVERFLOW , because we don ' t want to print an
* irrelevant hint about datestyle .
*/
DateTimeParseError ( DTERR_FIELD_OVERFLOW , date_str , " timestamp " ) ;
}
}
/* Range-check time fields too */
if ( tm - > tm_hour < 0 | | tm - > tm_hour > = HOURS_PER_DAY | |
tm - > tm_min < 0 | | tm - > tm_min > = MINS_PER_HOUR | |
tm - > tm_sec < 0 | | tm - > tm_sec > = SECS_PER_MINUTE | |
# ifdef HAVE_INT64_TIMESTAMP
* fsec < INT64CONST ( 0 ) | | * fsec > = USECS_PER_SEC
# else
* fsec < 0 | | * fsec > = 1
# endif
)
DateTimeParseError ( DTERR_FIELD_OVERFLOW , date_str , " timestamp " ) ;
DEBUG_TM ( tm ) ;
DEBUG_TM ( tm ) ;
pfree ( date_str ) ;
}
}