@ -4311,6 +4311,83 @@ date2isoyearday(int year, int mon, int mday)
return date2j ( year , mon , mday ) - isoweek2j ( date2isoyear ( year , mon , mday ) , 1 ) + 1 ;
}
/*
* NonFiniteTimestampTzPart
*
* Used by timestamp_part and timestamptz_part when extracting from infinite
* timestamp [ tz ] . Returns + / - Infinity if that is the appropriate result ,
* otherwise returns zero ( which should be taken as meaning to return NULL ) .
*
* Errors thrown here for invalid units should exactly match those that
* would be thrown in the calling functions , else there will be unexpected
* discrepancies between finite - and infinite - input cases .
*/
static float8
NonFiniteTimestampTzPart ( int type , int unit , char * lowunits ,
bool isNegative , bool isTz )
{
if ( ( type ! = UNITS ) & & ( type ! = RESERV ) )
{
if ( isTz )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " timestamp with time zone units \" %s \" not recognized " ,
lowunits ) ) ) ;
else
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " timestamp units \" %s \" not recognized " ,
lowunits ) ) ) ;
}
switch ( unit )
{
/* Oscillating units */
case DTK_MICROSEC :
case DTK_MILLISEC :
case DTK_SECOND :
case DTK_MINUTE :
case DTK_HOUR :
case DTK_DAY :
case DTK_MONTH :
case DTK_QUARTER :
case DTK_WEEK :
case DTK_DOW :
case DTK_ISODOW :
case DTK_DOY :
case DTK_TZ :
case DTK_TZ_MINUTE :
case DTK_TZ_HOUR :
return 0.0 ;
/* Monotonically-increasing units */
case DTK_YEAR :
case DTK_DECADE :
case DTK_CENTURY :
case DTK_MILLENNIUM :
case DTK_JULIAN :
case DTK_ISOYEAR :
case DTK_EPOCH :
if ( isNegative )
return - get_float8_infinity ( ) ;
else
return get_float8_infinity ( ) ;
default :
if ( isTz )
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " timestamp with time zone units \" %s \" not supported " ,
lowunits ) ) ) ;
else
ereport ( ERROR ,
( errcode ( ERRCODE_FEATURE_NOT_SUPPORTED ) ,
errmsg ( " timestamp units \" %s \" not supported " ,
lowunits ) ) ) ;
return 0.0 ; /* keep compiler quiet */
}
}
/* timestamp_part()
* Extract specified field from timestamp .
*/
@ -4327,12 +4404,6 @@ timestamp_part(PG_FUNCTION_ARGS)
struct pg_tm tt ,
* tm = & tt ;
if ( TIMESTAMP_NOT_FINITE ( timestamp ) )
{
result = 0 ;
PG_RETURN_FLOAT8 ( result ) ;
}
lowunits = downcase_truncate_identifier ( VARDATA_ANY ( units ) ,
VARSIZE_ANY_EXHDR ( units ) ,
false ) ;
@ -4341,6 +4412,17 @@ timestamp_part(PG_FUNCTION_ARGS)
if ( type = = UNKNOWN_FIELD )
type = DecodeSpecial ( 0 , lowunits , & val ) ;
if ( TIMESTAMP_NOT_FINITE ( timestamp ) )
{
result = NonFiniteTimestampTzPart ( type , val , lowunits ,
TIMESTAMP_IS_NOBEGIN ( timestamp ) ,
false ) ;
if ( result )
PG_RETURN_FLOAT8 ( result ) ;
else
PG_RETURN_NULL ( ) ;
}
if ( type = = UNITS )
{
if ( timestamp2tm ( timestamp , NULL , tm , & fsec , NULL , NULL ) ! = 0 )
@ -4538,12 +4620,6 @@ timestamptz_part(PG_FUNCTION_ARGS)
struct pg_tm tt ,
* tm = & tt ;
if ( TIMESTAMP_NOT_FINITE ( timestamp ) )
{
result = 0 ;
PG_RETURN_FLOAT8 ( result ) ;
}
lowunits = downcase_truncate_identifier ( VARDATA_ANY ( units ) ,
VARSIZE_ANY_EXHDR ( units ) ,
false ) ;
@ -4552,6 +4628,17 @@ timestamptz_part(PG_FUNCTION_ARGS)
if ( type = = UNKNOWN_FIELD )
type = DecodeSpecial ( 0 , lowunits , & val ) ;
if ( TIMESTAMP_NOT_FINITE ( timestamp ) )
{
result = NonFiniteTimestampTzPart ( type , val , lowunits ,
TIMESTAMP_IS_NOBEGIN ( timestamp ) ,
true ) ;
if ( result )
PG_RETURN_FLOAT8 ( result ) ;
else
PG_RETURN_NULL ( ) ;
}
if ( type = = UNITS )
{
if ( timestamp2tm ( timestamp , & tz , tm , & fsec , NULL , NULL ) ! = 0 )