LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 884 1184 74.7 %
Date: 2024-11-21 08:14:44 Functions: 105 144 72.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * date.c
       4             :  *    implements DATE and TIME data types specified in SQL standard
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994-5, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/adt/date.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include <ctype.h>
      19             : #include <limits.h>
      20             : #include <float.h>
      21             : #include <math.h>
      22             : #include <time.h>
      23             : 
      24             : #include "access/xact.h"
      25             : #include "catalog/pg_type.h"
      26             : #include "common/hashfn.h"
      27             : #include "common/int.h"
      28             : #include "libpq/pqformat.h"
      29             : #include "miscadmin.h"
      30             : #include "nodes/supportnodes.h"
      31             : #include "parser/scansup.h"
      32             : #include "utils/array.h"
      33             : #include "utils/builtins.h"
      34             : #include "utils/date.h"
      35             : #include "utils/datetime.h"
      36             : #include "utils/numeric.h"
      37             : #include "utils/sortsupport.h"
      38             : 
      39             : /*
      40             :  * gcc's -ffast-math switch breaks routines that expect exact results from
      41             :  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
      42             :  */
      43             : #ifdef __FAST_MATH__
      44             : #error -ffast-math is known to break this code
      45             : #endif
      46             : 
      47             : 
      48             : /* common code for timetypmodin and timetztypmodin */
      49             : static int32
      50          44 : anytime_typmodin(bool istz, ArrayType *ta)
      51             : {
      52             :     int32      *tl;
      53             :     int         n;
      54             : 
      55          44 :     tl = ArrayGetIntegerTypmods(ta, &n);
      56             : 
      57             :     /*
      58             :      * we're not too tense about good error message here because grammar
      59             :      * shouldn't allow wrong number of modifiers for TIME
      60             :      */
      61          44 :     if (n != 1)
      62           0 :         ereport(ERROR,
      63             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      64             :                  errmsg("invalid type modifier")));
      65             : 
      66          44 :     return anytime_typmod_check(istz, tl[0]);
      67             : }
      68             : 
      69             : /* exported so parse_expr.c can use it */
      70             : int32
      71         452 : anytime_typmod_check(bool istz, int32 typmod)
      72             : {
      73         452 :     if (typmod < 0)
      74           0 :         ereport(ERROR,
      75             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      76             :                  errmsg("TIME(%d)%s precision must not be negative",
      77             :                         typmod, (istz ? " WITH TIME ZONE" : ""))));
      78         452 :     if (typmod > MAX_TIME_PRECISION)
      79             :     {
      80          36 :         ereport(WARNING,
      81             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      82             :                  errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
      83             :                         typmod, (istz ? " WITH TIME ZONE" : ""),
      84             :                         MAX_TIME_PRECISION)));
      85          36 :         typmod = MAX_TIME_PRECISION;
      86             :     }
      87             : 
      88         452 :     return typmod;
      89             : }
      90             : 
      91             : /* common code for timetypmodout and timetztypmodout */
      92             : static char *
      93          20 : anytime_typmodout(bool istz, int32 typmod)
      94             : {
      95          20 :     const char *tz = istz ? " with time zone" : " without time zone";
      96             : 
      97          20 :     if (typmod >= 0)
      98          20 :         return psprintf("(%d)%s", (int) typmod, tz);
      99             :     else
     100           0 :         return pstrdup(tz);
     101             : }
     102             : 
     103             : 
     104             : /*****************************************************************************
     105             :  *   Date ADT
     106             :  *****************************************************************************/
     107             : 
     108             : 
     109             : /* date_in()
     110             :  * Given date text string, convert to internal date format.
     111             :  */
     112             : Datum
     113       11358 : date_in(PG_FUNCTION_ARGS)
     114             : {
     115       11358 :     char       *str = PG_GETARG_CSTRING(0);
     116       11358 :     Node       *escontext = fcinfo->context;
     117             :     DateADT     date;
     118             :     fsec_t      fsec;
     119             :     struct pg_tm tt,
     120       11358 :                *tm = &tt;
     121             :     int         tzp;
     122             :     int         dtype;
     123             :     int         nf;
     124             :     int         dterr;
     125             :     char       *field[MAXDATEFIELDS];
     126             :     int         ftype[MAXDATEFIELDS];
     127             :     char        workbuf[MAXDATELEN + 1];
     128             :     DateTimeErrorExtra extra;
     129             : 
     130       11358 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     131             :                           field, ftype, MAXDATEFIELDS, &nf);
     132       11358 :     if (dterr == 0)
     133       11358 :         dterr = DecodeDateTime(field, ftype, nf,
     134             :                                &dtype, tm, &fsec, &tzp, &extra);
     135       11358 :     if (dterr != 0)
     136             :     {
     137         294 :         DateTimeParseError(dterr, &extra, str, "date", escontext);
     138          12 :         PG_RETURN_NULL();
     139             :     }
     140             : 
     141       11064 :     switch (dtype)
     142             :     {
     143       10740 :         case DTK_DATE:
     144       10740 :             break;
     145             : 
     146           6 :         case DTK_EPOCH:
     147           6 :             GetEpochTime(tm);
     148           6 :             break;
     149             : 
     150         210 :         case DTK_LATE:
     151         210 :             DATE_NOEND(date);
     152         210 :             PG_RETURN_DATEADT(date);
     153             : 
     154         108 :         case DTK_EARLY:
     155         108 :             DATE_NOBEGIN(date);
     156         108 :             PG_RETURN_DATEADT(date);
     157             : 
     158           0 :         default:
     159           0 :             DateTimeParseError(DTERR_BAD_FORMAT, &extra, str, "date", escontext);
     160           0 :             PG_RETURN_NULL();
     161             :     }
     162             : 
     163             :     /* Prevent overflow in Julian-day routines */
     164       10746 :     if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
     165          12 :         ereturn(escontext, (Datum) 0,
     166             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     167             :                  errmsg("date out of range: \"%s\"", str)));
     168             : 
     169       10734 :     date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
     170             : 
     171             :     /* Now check for just-out-of-range dates */
     172       10734 :     if (!IS_VALID_DATE(date))
     173          12 :         ereturn(escontext, (Datum) 0,
     174             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     175             :                  errmsg("date out of range: \"%s\"", str)));
     176             : 
     177       10722 :     PG_RETURN_DATEADT(date);
     178             : }
     179             : 
     180             : /* date_out()
     181             :  * Given internal format date, convert to text string.
     182             :  */
     183             : Datum
     184       12138 : date_out(PG_FUNCTION_ARGS)
     185             : {
     186       12138 :     DateADT     date = PG_GETARG_DATEADT(0);
     187             :     char       *result;
     188             :     struct pg_tm tt,
     189       12138 :                *tm = &tt;
     190             :     char        buf[MAXDATELEN + 1];
     191             : 
     192       12138 :     if (DATE_NOT_FINITE(date))
     193         144 :         EncodeSpecialDate(date, buf);
     194             :     else
     195             :     {
     196       11994 :         j2date(date + POSTGRES_EPOCH_JDATE,
     197             :                &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
     198       11994 :         EncodeDateOnly(tm, DateStyle, buf);
     199             :     }
     200             : 
     201       12138 :     result = pstrdup(buf);
     202       12138 :     PG_RETURN_CSTRING(result);
     203             : }
     204             : 
     205             : /*
     206             :  *      date_recv           - converts external binary format to date
     207             :  */
     208             : Datum
     209           0 : date_recv(PG_FUNCTION_ARGS)
     210             : {
     211           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     212             :     DateADT     result;
     213             : 
     214           0 :     result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
     215             : 
     216             :     /* Limit to the same range that date_in() accepts. */
     217           0 :     if (DATE_NOT_FINITE(result))
     218             :          /* ok */ ;
     219           0 :     else if (!IS_VALID_DATE(result))
     220           0 :         ereport(ERROR,
     221             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     222             :                  errmsg("date out of range")));
     223             : 
     224           0 :     PG_RETURN_DATEADT(result);
     225             : }
     226             : 
     227             : /*
     228             :  *      date_send           - converts date to binary format
     229             :  */
     230             : Datum
     231           0 : date_send(PG_FUNCTION_ARGS)
     232             : {
     233           0 :     DateADT     date = PG_GETARG_DATEADT(0);
     234             :     StringInfoData buf;
     235             : 
     236           0 :     pq_begintypsend(&buf);
     237           0 :     pq_sendint32(&buf, date);
     238           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     239             : }
     240             : 
     241             : /*
     242             :  *      make_date           - date constructor
     243             :  */
     244             : Datum
     245          36 : make_date(PG_FUNCTION_ARGS)
     246             : {
     247             :     struct pg_tm tm;
     248             :     DateADT     date;
     249             :     int         dterr;
     250          36 :     bool        bc = false;
     251             : 
     252          36 :     tm.tm_year = PG_GETARG_INT32(0);
     253          36 :     tm.tm_mon = PG_GETARG_INT32(1);
     254          36 :     tm.tm_mday = PG_GETARG_INT32(2);
     255             : 
     256             :     /* Handle negative years as BC */
     257          36 :     if (tm.tm_year < 0)
     258             :     {
     259           6 :         bc = true;
     260           6 :         tm.tm_year = -tm.tm_year;
     261             :     }
     262             : 
     263          36 :     dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
     264             : 
     265          36 :     if (dterr != 0)
     266          24 :         ereport(ERROR,
     267             :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
     268             :                  errmsg("date field value out of range: %d-%02d-%02d",
     269             :                         tm.tm_year, tm.tm_mon, tm.tm_mday)));
     270             : 
     271             :     /* Prevent overflow in Julian-day routines */
     272          12 :     if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
     273           0 :         ereport(ERROR,
     274             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     275             :                  errmsg("date out of range: %d-%02d-%02d",
     276             :                         tm.tm_year, tm.tm_mon, tm.tm_mday)));
     277             : 
     278          12 :     date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
     279             : 
     280             :     /* Now check for just-out-of-range dates */
     281          12 :     if (!IS_VALID_DATE(date))
     282           0 :         ereport(ERROR,
     283             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     284             :                  errmsg("date out of range: %d-%02d-%02d",
     285             :                         tm.tm_year, tm.tm_mon, tm.tm_mday)));
     286             : 
     287          12 :     PG_RETURN_DATEADT(date);
     288             : }
     289             : 
     290             : /*
     291             :  * Convert reserved date values to string.
     292             :  */
     293             : void
     294         168 : EncodeSpecialDate(DateADT dt, char *str)
     295             : {
     296         168 :     if (DATE_IS_NOBEGIN(dt))
     297          84 :         strcpy(str, EARLY);
     298          84 :     else if (DATE_IS_NOEND(dt))
     299          84 :         strcpy(str, LATE);
     300             :     else                        /* shouldn't happen */
     301           0 :         elog(ERROR, "invalid argument for EncodeSpecialDate");
     302         168 : }
     303             : 
     304             : 
     305             : /*
     306             :  * GetSQLCurrentDate -- implements CURRENT_DATE
     307             :  */
     308             : DateADT
     309          50 : GetSQLCurrentDate(void)
     310             : {
     311             :     struct pg_tm tm;
     312             : 
     313             :     static int  cache_year = 0;
     314             :     static int  cache_mon = 0;
     315             :     static int  cache_mday = 0;
     316             :     static DateADT cache_date;
     317             : 
     318          50 :     GetCurrentDateTime(&tm);
     319             : 
     320             :     /*
     321             :      * date2j involves several integer divisions; moreover, unless our session
     322             :      * lives across local midnight, we don't really have to do it more than
     323             :      * once.  So it seems worth having a separate cache here.
     324             :      */
     325          50 :     if (tm.tm_year != cache_year ||
     326          18 :         tm.tm_mon != cache_mon ||
     327          18 :         tm.tm_mday != cache_mday)
     328             :     {
     329          32 :         cache_date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
     330          32 :         cache_year = tm.tm_year;
     331          32 :         cache_mon = tm.tm_mon;
     332          32 :         cache_mday = tm.tm_mday;
     333             :     }
     334             : 
     335          50 :     return cache_date;
     336             : }
     337             : 
     338             : /*
     339             :  * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
     340             :  */
     341             : TimeTzADT *
     342          24 : GetSQLCurrentTime(int32 typmod)
     343             : {
     344             :     TimeTzADT  *result;
     345             :     struct pg_tm tt,
     346          24 :                *tm = &tt;
     347             :     fsec_t      fsec;
     348             :     int         tz;
     349             : 
     350          24 :     GetCurrentTimeUsec(tm, &fsec, &tz);
     351             : 
     352          24 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
     353          24 :     tm2timetz(tm, fsec, tz, result);
     354          24 :     AdjustTimeForTypmod(&(result->time), typmod);
     355          24 :     return result;
     356             : }
     357             : 
     358             : /*
     359             :  * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
     360             :  */
     361             : TimeADT
     362          24 : GetSQLLocalTime(int32 typmod)
     363             : {
     364             :     TimeADT     result;
     365             :     struct pg_tm tt,
     366          24 :                *tm = &tt;
     367             :     fsec_t      fsec;
     368             :     int         tz;
     369             : 
     370          24 :     GetCurrentTimeUsec(tm, &fsec, &tz);
     371             : 
     372          24 :     tm2time(tm, fsec, &result);
     373          24 :     AdjustTimeForTypmod(&result, typmod);
     374          24 :     return result;
     375             : }
     376             : 
     377             : 
     378             : /*
     379             :  * Comparison functions for dates
     380             :  */
     381             : 
     382             : Datum
     383       18556 : date_eq(PG_FUNCTION_ARGS)
     384             : {
     385       18556 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     386       18556 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     387             : 
     388       18556 :     PG_RETURN_BOOL(dateVal1 == dateVal2);
     389             : }
     390             : 
     391             : Datum
     392           0 : date_ne(PG_FUNCTION_ARGS)
     393             : {
     394           0 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     395           0 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     396             : 
     397           0 :     PG_RETURN_BOOL(dateVal1 != dateVal2);
     398             : }
     399             : 
     400             : Datum
     401       26174 : date_lt(PG_FUNCTION_ARGS)
     402             : {
     403       26174 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     404       26174 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     405             : 
     406       26174 :     PG_RETURN_BOOL(dateVal1 < dateVal2);
     407             : }
     408             : 
     409             : Datum
     410        6774 : date_le(PG_FUNCTION_ARGS)
     411             : {
     412        6774 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     413        6774 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     414             : 
     415        6774 :     PG_RETURN_BOOL(dateVal1 <= dateVal2);
     416             : }
     417             : 
     418             : Datum
     419        8412 : date_gt(PG_FUNCTION_ARGS)
     420             : {
     421        8412 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     422        8412 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     423             : 
     424        8412 :     PG_RETURN_BOOL(dateVal1 > dateVal2);
     425             : }
     426             : 
     427             : Datum
     428        6472 : date_ge(PG_FUNCTION_ARGS)
     429             : {
     430        6472 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     431        6472 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     432             : 
     433        6472 :     PG_RETURN_BOOL(dateVal1 >= dateVal2);
     434             : }
     435             : 
     436             : Datum
     437       33782 : date_cmp(PG_FUNCTION_ARGS)
     438             : {
     439       33782 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     440       33782 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     441             : 
     442       33782 :     if (dateVal1 < dateVal2)
     443       18882 :         PG_RETURN_INT32(-1);
     444       14900 :     else if (dateVal1 > dateVal2)
     445       10536 :         PG_RETURN_INT32(1);
     446        4364 :     PG_RETURN_INT32(0);
     447             : }
     448             : 
     449             : Datum
     450         592 : date_sortsupport(PG_FUNCTION_ARGS)
     451             : {
     452         592 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     453             : 
     454         592 :     ssup->comparator = ssup_datum_int32_cmp;
     455         592 :     PG_RETURN_VOID();
     456             : }
     457             : 
     458             : Datum
     459         268 : hashdate(PG_FUNCTION_ARGS)
     460             : {
     461         268 :     return hash_uint32(PG_GETARG_DATEADT(0));
     462             : }
     463             : 
     464             : Datum
     465           0 : hashdateextended(PG_FUNCTION_ARGS)
     466             : {
     467           0 :     return hash_uint32_extended(PG_GETARG_DATEADT(0), PG_GETARG_INT64(1));
     468             : }
     469             : 
     470             : Datum
     471          18 : date_finite(PG_FUNCTION_ARGS)
     472             : {
     473          18 :     DateADT     date = PG_GETARG_DATEADT(0);
     474             : 
     475          18 :     PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
     476             : }
     477             : 
     478             : Datum
     479          16 : date_larger(PG_FUNCTION_ARGS)
     480             : {
     481          16 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     482          16 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     483             : 
     484          16 :     PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
     485             : }
     486             : 
     487             : Datum
     488           0 : date_smaller(PG_FUNCTION_ARGS)
     489             : {
     490           0 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     491           0 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     492             : 
     493           0 :     PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
     494             : }
     495             : 
     496             : /* Compute difference between two dates in days.
     497             :  */
     498             : Datum
     499        3430 : date_mi(PG_FUNCTION_ARGS)
     500             : {
     501        3430 :     DateADT     dateVal1 = PG_GETARG_DATEADT(0);
     502        3430 :     DateADT     dateVal2 = PG_GETARG_DATEADT(1);
     503             : 
     504        3430 :     if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
     505           0 :         ereport(ERROR,
     506             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     507             :                  errmsg("cannot subtract infinite dates")));
     508             : 
     509        3430 :     PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
     510             : }
     511             : 
     512             : /* Add a number of days to a date, giving a new date.
     513             :  * Must handle both positive and negative numbers of days.
     514             :  */
     515             : Datum
     516        2652 : date_pli(PG_FUNCTION_ARGS)
     517             : {
     518        2652 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     519        2652 :     int32       days = PG_GETARG_INT32(1);
     520             :     DateADT     result;
     521             : 
     522        2652 :     if (DATE_NOT_FINITE(dateVal))
     523           0 :         PG_RETURN_DATEADT(dateVal); /* can't change infinity */
     524             : 
     525        2652 :     result = dateVal + days;
     526             : 
     527             :     /* Check for integer overflow and out-of-allowed-range */
     528        2652 :     if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
     529        2652 :         !IS_VALID_DATE(result))
     530           0 :         ereport(ERROR,
     531             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     532             :                  errmsg("date out of range")));
     533             : 
     534        2652 :     PG_RETURN_DATEADT(result);
     535             : }
     536             : 
     537             : /* Subtract a number of days from a date, giving a new date.
     538             :  */
     539             : Datum
     540          36 : date_mii(PG_FUNCTION_ARGS)
     541             : {
     542          36 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     543          36 :     int32       days = PG_GETARG_INT32(1);
     544             :     DateADT     result;
     545             : 
     546          36 :     if (DATE_NOT_FINITE(dateVal))
     547           0 :         PG_RETURN_DATEADT(dateVal); /* can't change infinity */
     548             : 
     549          36 :     result = dateVal - days;
     550             : 
     551             :     /* Check for integer overflow and out-of-allowed-range */
     552          36 :     if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
     553          36 :         !IS_VALID_DATE(result))
     554           0 :         ereport(ERROR,
     555             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     556             :                  errmsg("date out of range")));
     557             : 
     558          36 :     PG_RETURN_DATEADT(result);
     559             : }
     560             : 
     561             : 
     562             : /*
     563             :  * Promote date to timestamp.
     564             :  *
     565             :  * On successful conversion, *overflow is set to zero if it's not NULL.
     566             :  *
     567             :  * If the date is finite but out of the valid range for timestamp, then:
     568             :  * if overflow is NULL, we throw an out-of-range error.
     569             :  * if overflow is not NULL, we store +1 or -1 there to indicate the sign
     570             :  * of the overflow, and return the appropriate timestamp infinity.
     571             :  *
     572             :  * Note: *overflow = -1 is actually not possible currently, since both
     573             :  * datatypes have the same lower bound, Julian day zero.
     574             :  */
     575             : Timestamp
     576        4452 : date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
     577             : {
     578             :     Timestamp   result;
     579             : 
     580        4452 :     if (overflow)
     581         198 :         *overflow = 0;
     582             : 
     583        4452 :     if (DATE_IS_NOBEGIN(dateVal))
     584          24 :         TIMESTAMP_NOBEGIN(result);
     585        4428 :     else if (DATE_IS_NOEND(dateVal))
     586          24 :         TIMESTAMP_NOEND(result);
     587             :     else
     588             :     {
     589             :         /*
     590             :          * Since dates have the same minimum values as timestamps, only upper
     591             :          * boundary need be checked for overflow.
     592             :          */
     593        4404 :         if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
     594             :         {
     595          24 :             if (overflow)
     596             :             {
     597          18 :                 *overflow = 1;
     598          18 :                 TIMESTAMP_NOEND(result);
     599          18 :                 return result;
     600             :             }
     601             :             else
     602             :             {
     603           6 :                 ereport(ERROR,
     604             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     605             :                          errmsg("date out of range for timestamp")));
     606             :             }
     607             :         }
     608             : 
     609             :         /* date is days since 2000, timestamp is microseconds since same... */
     610        4380 :         result = dateVal * USECS_PER_DAY;
     611             :     }
     612             : 
     613        4428 :     return result;
     614             : }
     615             : 
     616             : /*
     617             :  * Promote date to timestamp, throwing error for overflow.
     618             :  */
     619             : static TimestampTz
     620        4254 : date2timestamp(DateADT dateVal)
     621             : {
     622        4254 :     return date2timestamp_opt_overflow(dateVal, NULL);
     623             : }
     624             : 
     625             : /*
     626             :  * Promote date to timestamp with time zone.
     627             :  *
     628             :  * On successful conversion, *overflow is set to zero if it's not NULL.
     629             :  *
     630             :  * If the date is finite but out of the valid range for timestamptz, then:
     631             :  * if overflow is NULL, we throw an out-of-range error.
     632             :  * if overflow is not NULL, we store +1 or -1 there to indicate the sign
     633             :  * of the overflow, and return the appropriate timestamptz infinity.
     634             :  */
     635             : TimestampTz
     636         386 : date2timestamptz_opt_overflow(DateADT dateVal, int *overflow)
     637             : {
     638             :     TimestampTz result;
     639             :     struct pg_tm tt,
     640         386 :                *tm = &tt;
     641             :     int         tz;
     642             : 
     643         386 :     if (overflow)
     644         168 :         *overflow = 0;
     645             : 
     646         386 :     if (DATE_IS_NOBEGIN(dateVal))
     647           0 :         TIMESTAMP_NOBEGIN(result);
     648         386 :     else if (DATE_IS_NOEND(dateVal))
     649           0 :         TIMESTAMP_NOEND(result);
     650             :     else
     651             :     {
     652             :         /*
     653             :          * Since dates have the same minimum values as timestamps, only upper
     654             :          * boundary need be checked for overflow.
     655             :          */
     656         386 :         if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
     657             :         {
     658          18 :             if (overflow)
     659             :             {
     660          12 :                 *overflow = 1;
     661          12 :                 TIMESTAMP_NOEND(result);
     662          12 :                 return result;
     663             :             }
     664             :             else
     665             :             {
     666           6 :                 ereport(ERROR,
     667             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     668             :                          errmsg("date out of range for timestamp")));
     669             :             }
     670             :         }
     671             : 
     672         368 :         j2date(dateVal + POSTGRES_EPOCH_JDATE,
     673             :                &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
     674         368 :         tm->tm_hour = 0;
     675         368 :         tm->tm_min = 0;
     676         368 :         tm->tm_sec = 0;
     677         368 :         tz = DetermineTimeZoneOffset(tm, session_timezone);
     678             : 
     679         368 :         result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
     680             : 
     681             :         /*
     682             :          * Since it is possible to go beyond allowed timestamptz range because
     683             :          * of time zone, check for allowed timestamp range after adding tz.
     684             :          */
     685         368 :         if (!IS_VALID_TIMESTAMP(result))
     686             :         {
     687          18 :             if (overflow)
     688             :             {
     689          12 :                 if (result < MIN_TIMESTAMP)
     690             :                 {
     691          12 :                     *overflow = -1;
     692          12 :                     TIMESTAMP_NOBEGIN(result);
     693             :                 }
     694             :                 else
     695             :                 {
     696           0 :                     *overflow = 1;
     697           0 :                     TIMESTAMP_NOEND(result);
     698             :                 }
     699             :             }
     700             :             else
     701             :             {
     702           6 :                 ereport(ERROR,
     703             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     704             :                          errmsg("date out of range for timestamp")));
     705             :             }
     706             :         }
     707             :     }
     708             : 
     709         362 :     return result;
     710             : }
     711             : 
     712             : /*
     713             :  * Promote date to timestamptz, throwing error for overflow.
     714             :  */
     715             : static TimestampTz
     716         218 : date2timestamptz(DateADT dateVal)
     717             : {
     718         218 :     return date2timestamptz_opt_overflow(dateVal, NULL);
     719             : }
     720             : 
     721             : /*
     722             :  * date2timestamp_no_overflow
     723             :  *
     724             :  * This is chartered to produce a double value that is numerically
     725             :  * equivalent to the corresponding Timestamp value, if the date is in the
     726             :  * valid range of Timestamps, but in any case not throw an overflow error.
     727             :  * We can do this since the numerical range of double is greater than
     728             :  * that of non-erroneous timestamps.  The results are currently only
     729             :  * used for statistical estimation purposes.
     730             :  */
     731             : double
     732           0 : date2timestamp_no_overflow(DateADT dateVal)
     733             : {
     734             :     double      result;
     735             : 
     736           0 :     if (DATE_IS_NOBEGIN(dateVal))
     737           0 :         result = -DBL_MAX;
     738           0 :     else if (DATE_IS_NOEND(dateVal))
     739           0 :         result = DBL_MAX;
     740             :     else
     741             :     {
     742             :         /* date is days since 2000, timestamp is microseconds since same... */
     743           0 :         result = dateVal * (double) USECS_PER_DAY;
     744             :     }
     745             : 
     746           0 :     return result;
     747             : }
     748             : 
     749             : 
     750             : /*
     751             :  * Crosstype comparison functions for dates
     752             :  */
     753             : 
     754             : int32
     755         198 : date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
     756             : {
     757             :     Timestamp   dt1;
     758             :     int         overflow;
     759             : 
     760         198 :     dt1 = date2timestamp_opt_overflow(dateVal, &overflow);
     761         198 :     if (overflow > 0)
     762             :     {
     763             :         /* dt1 is larger than any finite timestamp, but less than infinity */
     764          18 :         return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
     765             :     }
     766             :     Assert(overflow == 0);      /* -1 case cannot occur */
     767             : 
     768         180 :     return timestamp_cmp_internal(dt1, dt2);
     769             : }
     770             : 
     771             : Datum
     772           0 : date_eq_timestamp(PG_FUNCTION_ARGS)
     773             : {
     774           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     775           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     776             : 
     777           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) == 0);
     778             : }
     779             : 
     780             : Datum
     781           0 : date_ne_timestamp(PG_FUNCTION_ARGS)
     782             : {
     783           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     784           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     785             : 
     786           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) != 0);
     787             : }
     788             : 
     789             : Datum
     790           0 : date_lt_timestamp(PG_FUNCTION_ARGS)
     791             : {
     792           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     793           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     794             : 
     795           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) < 0);
     796             : }
     797             : 
     798             : Datum
     799           6 : date_gt_timestamp(PG_FUNCTION_ARGS)
     800             : {
     801           6 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     802           6 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     803             : 
     804           6 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) > 0);
     805             : }
     806             : 
     807             : Datum
     808           0 : date_le_timestamp(PG_FUNCTION_ARGS)
     809             : {
     810           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     811           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     812             : 
     813           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) <= 0);
     814             : }
     815             : 
     816             : Datum
     817           0 : date_ge_timestamp(PG_FUNCTION_ARGS)
     818             : {
     819           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     820           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     821             : 
     822           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) >= 0);
     823             : }
     824             : 
     825             : Datum
     826           0 : date_cmp_timestamp(PG_FUNCTION_ARGS)
     827             : {
     828           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     829           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
     830             : 
     831           0 :     PG_RETURN_INT32(date_cmp_timestamp_internal(dateVal, dt2));
     832             : }
     833             : 
     834             : int32
     835         168 : date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
     836             : {
     837             :     TimestampTz dt1;
     838             :     int         overflow;
     839             : 
     840         168 :     dt1 = date2timestamptz_opt_overflow(dateVal, &overflow);
     841         168 :     if (overflow > 0)
     842             :     {
     843             :         /* dt1 is larger than any finite timestamp, but less than infinity */
     844          12 :         return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
     845             :     }
     846         156 :     if (overflow < 0)
     847             :     {
     848             :         /* dt1 is less than any finite timestamp, but more than -infinity */
     849          12 :         return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
     850             :     }
     851             : 
     852         144 :     return timestamptz_cmp_internal(dt1, dt2);
     853             : }
     854             : 
     855             : Datum
     856           0 : date_eq_timestamptz(PG_FUNCTION_ARGS)
     857             : {
     858           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     859           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     860             : 
     861           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) == 0);
     862             : }
     863             : 
     864             : Datum
     865           0 : date_ne_timestamptz(PG_FUNCTION_ARGS)
     866             : {
     867           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     868           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     869             : 
     870           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) != 0);
     871             : }
     872             : 
     873             : Datum
     874           6 : date_lt_timestamptz(PG_FUNCTION_ARGS)
     875             : {
     876           6 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     877           6 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     878             : 
     879           6 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) < 0);
     880             : }
     881             : 
     882             : Datum
     883           6 : date_gt_timestamptz(PG_FUNCTION_ARGS)
     884             : {
     885           6 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     886           6 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     887             : 
     888           6 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) > 0);
     889             : }
     890             : 
     891             : Datum
     892           0 : date_le_timestamptz(PG_FUNCTION_ARGS)
     893             : {
     894           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     895           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     896             : 
     897           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) <= 0);
     898             : }
     899             : 
     900             : Datum
     901           0 : date_ge_timestamptz(PG_FUNCTION_ARGS)
     902             : {
     903           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     904           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     905             : 
     906           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) >= 0);
     907             : }
     908             : 
     909             : Datum
     910           0 : date_cmp_timestamptz(PG_FUNCTION_ARGS)
     911             : {
     912           0 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
     913           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
     914             : 
     915           0 :     PG_RETURN_INT32(date_cmp_timestamptz_internal(dateVal, dt2));
     916             : }
     917             : 
     918             : Datum
     919           0 : timestamp_eq_date(PG_FUNCTION_ARGS)
     920             : {
     921           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     922           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     923             : 
     924           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) == 0);
     925             : }
     926             : 
     927             : Datum
     928           0 : timestamp_ne_date(PG_FUNCTION_ARGS)
     929             : {
     930           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     931           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     932             : 
     933           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) != 0);
     934             : }
     935             : 
     936             : Datum
     937           0 : timestamp_lt_date(PG_FUNCTION_ARGS)
     938             : {
     939           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     940           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     941             : 
     942           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) > 0);
     943             : }
     944             : 
     945             : Datum
     946           6 : timestamp_gt_date(PG_FUNCTION_ARGS)
     947             : {
     948           6 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     949           6 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     950             : 
     951           6 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) < 0);
     952             : }
     953             : 
     954             : Datum
     955           0 : timestamp_le_date(PG_FUNCTION_ARGS)
     956             : {
     957           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     958           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     959             : 
     960           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) >= 0);
     961             : }
     962             : 
     963             : Datum
     964           0 : timestamp_ge_date(PG_FUNCTION_ARGS)
     965             : {
     966           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     967           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     968             : 
     969           0 :     PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) <= 0);
     970             : }
     971             : 
     972             : Datum
     973           0 : timestamp_cmp_date(PG_FUNCTION_ARGS)
     974             : {
     975           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
     976           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     977             : 
     978           0 :     PG_RETURN_INT32(-date_cmp_timestamp_internal(dateVal, dt1));
     979             : }
     980             : 
     981             : Datum
     982           0 : timestamptz_eq_date(PG_FUNCTION_ARGS)
     983             : {
     984           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
     985           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     986             : 
     987           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) == 0);
     988             : }
     989             : 
     990             : Datum
     991           0 : timestamptz_ne_date(PG_FUNCTION_ARGS)
     992             : {
     993           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
     994           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
     995             : 
     996           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) != 0);
     997             : }
     998             : 
     999             : Datum
    1000           0 : timestamptz_lt_date(PG_FUNCTION_ARGS)
    1001             : {
    1002           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    1003           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
    1004             : 
    1005           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) > 0);
    1006             : }
    1007             : 
    1008             : Datum
    1009           6 : timestamptz_gt_date(PG_FUNCTION_ARGS)
    1010             : {
    1011           6 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    1012           6 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
    1013             : 
    1014           6 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) < 0);
    1015             : }
    1016             : 
    1017             : Datum
    1018           0 : timestamptz_le_date(PG_FUNCTION_ARGS)
    1019             : {
    1020           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    1021           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
    1022             : 
    1023           0 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) >= 0);
    1024             : }
    1025             : 
    1026             : Datum
    1027           6 : timestamptz_ge_date(PG_FUNCTION_ARGS)
    1028             : {
    1029           6 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    1030           6 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
    1031             : 
    1032           6 :     PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) <= 0);
    1033             : }
    1034             : 
    1035             : Datum
    1036           0 : timestamptz_cmp_date(PG_FUNCTION_ARGS)
    1037             : {
    1038           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    1039           0 :     DateADT     dateVal = PG_GETARG_DATEADT(1);
    1040             : 
    1041           0 :     PG_RETURN_INT32(-date_cmp_timestamptz_internal(dateVal, dt1));
    1042             : }
    1043             : 
    1044             : /*
    1045             :  * in_range support function for date.
    1046             :  *
    1047             :  * We implement this by promoting the dates to timestamp (without time zone)
    1048             :  * and then using the timestamp-and-interval in_range function.
    1049             :  */
    1050             : Datum
    1051        1338 : in_range_date_interval(PG_FUNCTION_ARGS)
    1052             : {
    1053        1338 :     DateADT     val = PG_GETARG_DATEADT(0);
    1054        1338 :     DateADT     base = PG_GETARG_DATEADT(1);
    1055        1338 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    1056        1338 :     bool        sub = PG_GETARG_BOOL(3);
    1057        1338 :     bool        less = PG_GETARG_BOOL(4);
    1058             :     Timestamp   valStamp;
    1059             :     Timestamp   baseStamp;
    1060             : 
    1061             :     /* XXX we could support out-of-range cases here, perhaps */
    1062        1338 :     valStamp = date2timestamp(val);
    1063        1338 :     baseStamp = date2timestamp(base);
    1064             : 
    1065        1338 :     return DirectFunctionCall5(in_range_timestamp_interval,
    1066             :                                TimestampGetDatum(valStamp),
    1067             :                                TimestampGetDatum(baseStamp),
    1068             :                                IntervalPGetDatum(offset),
    1069             :                                BoolGetDatum(sub),
    1070             :                                BoolGetDatum(less));
    1071             : }
    1072             : 
    1073             : 
    1074             : /* extract_date()
    1075             :  * Extract specified field from date type.
    1076             :  */
    1077             : Datum
    1078         678 : extract_date(PG_FUNCTION_ARGS)
    1079             : {
    1080         678 :     text       *units = PG_GETARG_TEXT_PP(0);
    1081         678 :     DateADT     date = PG_GETARG_DATEADT(1);
    1082             :     int64       intresult;
    1083             :     int         type,
    1084             :                 val;
    1085             :     char       *lowunits;
    1086             :     int         year,
    1087             :                 mon,
    1088             :                 mday;
    1089             : 
    1090         678 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    1091         678 :                                             VARSIZE_ANY_EXHDR(units),
    1092             :                                             false);
    1093             : 
    1094         678 :     type = DecodeUnits(0, lowunits, &val);
    1095         678 :     if (type == UNKNOWN_FIELD)
    1096         114 :         type = DecodeSpecial(0, lowunits, &val);
    1097             : 
    1098         678 :     if (DATE_NOT_FINITE(date) && (type == UNITS || type == RESERV))
    1099             :     {
    1100         108 :         switch (val)
    1101             :         {
    1102             :                 /* Oscillating units */
    1103          54 :             case DTK_DAY:
    1104             :             case DTK_MONTH:
    1105             :             case DTK_QUARTER:
    1106             :             case DTK_WEEK:
    1107             :             case DTK_DOW:
    1108             :             case DTK_ISODOW:
    1109             :             case DTK_DOY:
    1110          54 :                 PG_RETURN_NULL();
    1111             :                 break;
    1112             : 
    1113             :                 /* Monotonically-increasing units */
    1114          54 :             case DTK_YEAR:
    1115             :             case DTK_DECADE:
    1116             :             case DTK_CENTURY:
    1117             :             case DTK_MILLENNIUM:
    1118             :             case DTK_JULIAN:
    1119             :             case DTK_ISOYEAR:
    1120             :             case DTK_EPOCH:
    1121          54 :                 if (DATE_IS_NOBEGIN(date))
    1122           6 :                     PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
    1123             :                                                                           CStringGetDatum("-Infinity"),
    1124             :                                                                           ObjectIdGetDatum(InvalidOid),
    1125             :                                                                           Int32GetDatum(-1))));
    1126             :                 else
    1127          48 :                     PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
    1128             :                                                                           CStringGetDatum("Infinity"),
    1129             :                                                                           ObjectIdGetDatum(InvalidOid),
    1130             :                                                                           Int32GetDatum(-1))));
    1131           0 :             default:
    1132           0 :                 ereport(ERROR,
    1133             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1134             :                          errmsg("unit \"%s\" not supported for type %s",
    1135             :                                 lowunits, format_type_be(DATEOID))));
    1136             :         }
    1137             :     }
    1138         570 :     else if (type == UNITS)
    1139             :     {
    1140         552 :         j2date(date + POSTGRES_EPOCH_JDATE, &year, &mon, &mday);
    1141             : 
    1142         552 :         switch (val)
    1143             :         {
    1144           6 :             case DTK_DAY:
    1145           6 :                 intresult = mday;
    1146           6 :                 break;
    1147             : 
    1148          90 :             case DTK_MONTH:
    1149          90 :                 intresult = mon;
    1150          90 :                 break;
    1151             : 
    1152           6 :             case DTK_QUARTER:
    1153           6 :                 intresult = (mon - 1) / 3 + 1;
    1154           6 :                 break;
    1155             : 
    1156           6 :             case DTK_WEEK:
    1157           6 :                 intresult = date2isoweek(year, mon, mday);
    1158           6 :                 break;
    1159             : 
    1160         186 :             case DTK_YEAR:
    1161         186 :                 if (year > 0)
    1162         180 :                     intresult = year;
    1163             :                 else
    1164             :                     /* there is no year 0, just 1 BC and 1 AD */
    1165           6 :                     intresult = year - 1;
    1166         186 :                 break;
    1167             : 
    1168          48 :             case DTK_DECADE:
    1169             :                 /* see comments in timestamp_part */
    1170          48 :                 if (year >= 0)
    1171          30 :                     intresult = year / 10;
    1172             :                 else
    1173          18 :                     intresult = -((8 - (year - 1)) / 10);
    1174          48 :                 break;
    1175             : 
    1176          66 :             case DTK_CENTURY:
    1177             :                 /* see comments in timestamp_part */
    1178          66 :                 if (year > 0)
    1179          48 :                     intresult = (year + 99) / 100;
    1180             :                 else
    1181          18 :                     intresult = -((99 - (year - 1)) / 100);
    1182          66 :                 break;
    1183             : 
    1184          48 :             case DTK_MILLENNIUM:
    1185             :                 /* see comments in timestamp_part */
    1186          48 :                 if (year > 0)
    1187          42 :                     intresult = (year + 999) / 1000;
    1188             :                 else
    1189           6 :                     intresult = -((999 - (year - 1)) / 1000);
    1190          48 :                 break;
    1191             : 
    1192           6 :             case DTK_JULIAN:
    1193           6 :                 intresult = date + POSTGRES_EPOCH_JDATE;
    1194           6 :                 break;
    1195             : 
    1196          12 :             case DTK_ISOYEAR:
    1197          12 :                 intresult = date2isoyear(year, mon, mday);
    1198             :                 /* Adjust BC years */
    1199          12 :                 if (intresult <= 0)
    1200           6 :                     intresult -= 1;
    1201          12 :                 break;
    1202             : 
    1203          24 :             case DTK_DOW:
    1204             :             case DTK_ISODOW:
    1205          24 :                 intresult = j2day(date + POSTGRES_EPOCH_JDATE);
    1206          24 :                 if (val == DTK_ISODOW && intresult == 0)
    1207           6 :                     intresult = 7;
    1208          24 :                 break;
    1209             : 
    1210           6 :             case DTK_DOY:
    1211           6 :                 intresult = date2j(year, mon, mday) - date2j(year, 1, 1) + 1;
    1212           6 :                 break;
    1213             : 
    1214          48 :             default:
    1215          48 :                 ereport(ERROR,
    1216             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1217             :                          errmsg("unit \"%s\" not supported for type %s",
    1218             :                                 lowunits, format_type_be(DATEOID))));
    1219             :                 intresult = 0;
    1220             :         }
    1221             :     }
    1222          18 :     else if (type == RESERV)
    1223             :     {
    1224          12 :         switch (val)
    1225             :         {
    1226          12 :             case DTK_EPOCH:
    1227          12 :                 intresult = ((int64) date + POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
    1228          12 :                 break;
    1229             : 
    1230           0 :             default:
    1231           0 :                 ereport(ERROR,
    1232             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1233             :                          errmsg("unit \"%s\" not supported for type %s",
    1234             :                                 lowunits, format_type_be(DATEOID))));
    1235             :                 intresult = 0;
    1236             :         }
    1237             :     }
    1238             :     else
    1239             :     {
    1240           6 :         ereport(ERROR,
    1241             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1242             :                  errmsg("unit \"%s\" not recognized for type %s",
    1243             :                         lowunits, format_type_be(DATEOID))));
    1244             :         intresult = 0;
    1245             :     }
    1246             : 
    1247         516 :     PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    1248             : }
    1249             : 
    1250             : 
    1251             : /* Add an interval to a date, giving a new date.
    1252             :  * Must handle both positive and negative intervals.
    1253             :  *
    1254             :  * We implement this by promoting the date to timestamp (without time zone)
    1255             :  * and then using the timestamp plus interval function.
    1256             :  */
    1257             : Datum
    1258          42 : date_pl_interval(PG_FUNCTION_ARGS)
    1259             : {
    1260          42 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
    1261          42 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    1262             :     Timestamp   dateStamp;
    1263             : 
    1264          42 :     dateStamp = date2timestamp(dateVal);
    1265             : 
    1266          42 :     return DirectFunctionCall2(timestamp_pl_interval,
    1267             :                                TimestampGetDatum(dateStamp),
    1268             :                                PointerGetDatum(span));
    1269             : }
    1270             : 
    1271             : /* Subtract an interval from a date, giving a new date.
    1272             :  * Must handle both positive and negative intervals.
    1273             :  *
    1274             :  * We implement this by promoting the date to timestamp (without time zone)
    1275             :  * and then using the timestamp minus interval function.
    1276             :  */
    1277             : Datum
    1278          48 : date_mi_interval(PG_FUNCTION_ARGS)
    1279             : {
    1280          48 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
    1281          48 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    1282             :     Timestamp   dateStamp;
    1283             : 
    1284          48 :     dateStamp = date2timestamp(dateVal);
    1285             : 
    1286          48 :     return DirectFunctionCall2(timestamp_mi_interval,
    1287             :                                TimestampGetDatum(dateStamp),
    1288             :                                PointerGetDatum(span));
    1289             : }
    1290             : 
    1291             : /* date_timestamp()
    1292             :  * Convert date to timestamp data type.
    1293             :  */
    1294             : Datum
    1295        1458 : date_timestamp(PG_FUNCTION_ARGS)
    1296             : {
    1297        1458 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
    1298             :     Timestamp   result;
    1299             : 
    1300        1458 :     result = date2timestamp(dateVal);
    1301             : 
    1302        1452 :     PG_RETURN_TIMESTAMP(result);
    1303             : }
    1304             : 
    1305             : /* timestamp_date()
    1306             :  * Convert timestamp to date data type.
    1307             :  */
    1308             : Datum
    1309        4018 : timestamp_date(PG_FUNCTION_ARGS)
    1310             : {
    1311        4018 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    1312             :     DateADT     result;
    1313             :     struct pg_tm tt,
    1314        4018 :                *tm = &tt;
    1315             :     fsec_t      fsec;
    1316             : 
    1317        4018 :     if (TIMESTAMP_IS_NOBEGIN(timestamp))
    1318           0 :         DATE_NOBEGIN(result);
    1319        4018 :     else if (TIMESTAMP_IS_NOEND(timestamp))
    1320           0 :         DATE_NOEND(result);
    1321             :     else
    1322             :     {
    1323        4018 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    1324           0 :             ereport(ERROR,
    1325             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1326             :                      errmsg("timestamp out of range")));
    1327             : 
    1328        4018 :         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
    1329             :     }
    1330             : 
    1331        4018 :     PG_RETURN_DATEADT(result);
    1332             : }
    1333             : 
    1334             : 
    1335             : /* date_timestamptz()
    1336             :  * Convert date to timestamp with time zone data type.
    1337             :  */
    1338             : Datum
    1339         218 : date_timestamptz(PG_FUNCTION_ARGS)
    1340             : {
    1341         218 :     DateADT     dateVal = PG_GETARG_DATEADT(0);
    1342             :     TimestampTz result;
    1343             : 
    1344         218 :     result = date2timestamptz(dateVal);
    1345             : 
    1346         206 :     PG_RETURN_TIMESTAMP(result);
    1347             : }
    1348             : 
    1349             : 
    1350             : /* timestamptz_date()
    1351             :  * Convert timestamp with time zone to date data type.
    1352             :  */
    1353             : Datum
    1354        3924 : timestamptz_date(PG_FUNCTION_ARGS)
    1355             : {
    1356        3924 :     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
    1357             :     DateADT     result;
    1358             :     struct pg_tm tt,
    1359        3924 :                *tm = &tt;
    1360             :     fsec_t      fsec;
    1361             :     int         tz;
    1362             : 
    1363        3924 :     if (TIMESTAMP_IS_NOBEGIN(timestamp))
    1364           0 :         DATE_NOBEGIN(result);
    1365        3924 :     else if (TIMESTAMP_IS_NOEND(timestamp))
    1366           0 :         DATE_NOEND(result);
    1367             :     else
    1368             :     {
    1369        3924 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    1370           0 :             ereport(ERROR,
    1371             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1372             :                      errmsg("timestamp out of range")));
    1373             : 
    1374        3924 :         result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
    1375             :     }
    1376             : 
    1377        3924 :     PG_RETURN_DATEADT(result);
    1378             : }
    1379             : 
    1380             : 
    1381             : /*****************************************************************************
    1382             :  *   Time ADT
    1383             :  *****************************************************************************/
    1384             : 
    1385             : Datum
    1386        2130 : time_in(PG_FUNCTION_ARGS)
    1387             : {
    1388        2130 :     char       *str = PG_GETARG_CSTRING(0);
    1389             : #ifdef NOT_USED
    1390             :     Oid         typelem = PG_GETARG_OID(1);
    1391             : #endif
    1392        2130 :     int32       typmod = PG_GETARG_INT32(2);
    1393        2130 :     Node       *escontext = fcinfo->context;
    1394             :     TimeADT     result;
    1395             :     fsec_t      fsec;
    1396             :     struct pg_tm tt,
    1397        2130 :                *tm = &tt;
    1398             :     int         tz;
    1399             :     int         nf;
    1400             :     int         dterr;
    1401             :     char        workbuf[MAXDATELEN + 1];
    1402             :     char       *field[MAXDATEFIELDS];
    1403             :     int         dtype;
    1404             :     int         ftype[MAXDATEFIELDS];
    1405             :     DateTimeErrorExtra extra;
    1406             : 
    1407        2130 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
    1408             :                           field, ftype, MAXDATEFIELDS, &nf);
    1409        2130 :     if (dterr == 0)
    1410        2130 :         dterr = DecodeTimeOnly(field, ftype, nf,
    1411             :                                &dtype, tm, &fsec, &tz, &extra);
    1412        2130 :     if (dterr != 0)
    1413             :     {
    1414          60 :         DateTimeParseError(dterr, &extra, str, "time", escontext);
    1415          24 :         PG_RETURN_NULL();
    1416             :     }
    1417             : 
    1418        2070 :     tm2time(tm, fsec, &result);
    1419        2070 :     AdjustTimeForTypmod(&result, typmod);
    1420             : 
    1421        2070 :     PG_RETURN_TIMEADT(result);
    1422             : }
    1423             : 
    1424             : /* tm2time()
    1425             :  * Convert a tm structure to a time data type.
    1426             :  */
    1427             : int
    1428        3456 : tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
    1429             : {
    1430        3456 :     *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
    1431        3456 :                * USECS_PER_SEC) + fsec;
    1432        3456 :     return 0;
    1433             : }
    1434             : 
    1435             : /* time_overflows()
    1436             :  * Check to see if a broken-down time-of-day is out of range.
    1437             :  */
    1438             : bool
    1439       58932 : time_overflows(int hour, int min, int sec, fsec_t fsec)
    1440             : {
    1441             :     /* Range-check the fields individually. */
    1442       58932 :     if (hour < 0 || hour > HOURS_PER_DAY ||
    1443       58896 :         min < 0 || min >= MINS_PER_HOUR ||
    1444       58896 :         sec < 0 || sec > SECS_PER_MINUTE ||
    1445       58896 :         fsec < 0 || fsec > USECS_PER_SEC)
    1446          36 :         return true;
    1447             : 
    1448             :     /*
    1449             :      * Because we allow, eg, hour = 24 or sec = 60, we must check separately
    1450             :      * that the total time value doesn't exceed 24:00:00.
    1451             :      */
    1452       58896 :     if ((((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
    1453       58896 :            + sec) * USECS_PER_SEC) + fsec) > USECS_PER_DAY)
    1454          36 :         return true;
    1455             : 
    1456       58860 :     return false;
    1457             : }
    1458             : 
    1459             : /* float_time_overflows()
    1460             :  * Same, when we have seconds + fractional seconds as one "double" value.
    1461             :  */
    1462             : bool
    1463         240 : float_time_overflows(int hour, int min, double sec)
    1464             : {
    1465             :     /* Range-check the fields individually. */
    1466         240 :     if (hour < 0 || hour > HOURS_PER_DAY ||
    1467         240 :         min < 0 || min >= MINS_PER_HOUR)
    1468           0 :         return true;
    1469             : 
    1470             :     /*
    1471             :      * "sec", being double, requires extra care.  Cope with NaN, and round off
    1472             :      * before applying the range check to avoid unexpected errors due to
    1473             :      * imprecise input.  (We assume rint() behaves sanely with infinities.)
    1474             :      */
    1475         240 :     if (isnan(sec))
    1476           0 :         return true;
    1477         240 :     sec = rint(sec * USECS_PER_SEC);
    1478         240 :     if (sec < 0 || sec > SECS_PER_MINUTE * USECS_PER_SEC)
    1479           6 :         return true;
    1480             : 
    1481             :     /*
    1482             :      * Because we allow, eg, hour = 24 or sec = 60, we must check separately
    1483             :      * that the total time value doesn't exceed 24:00:00.  This must match the
    1484             :      * way that callers will convert the fields to a time.
    1485             :      */
    1486         234 :     if (((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
    1487         234 :           * USECS_PER_SEC) + (int64) sec) > USECS_PER_DAY)
    1488           6 :         return true;
    1489             : 
    1490         228 :     return false;
    1491             : }
    1492             : 
    1493             : 
    1494             : /* time2tm()
    1495             :  * Convert time data type to POSIX time structure.
    1496             :  *
    1497             :  * Note that only the hour/min/sec/fractional-sec fields are filled in.
    1498             :  */
    1499             : int
    1500        6238 : time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
    1501             : {
    1502        6238 :     tm->tm_hour = time / USECS_PER_HOUR;
    1503        6238 :     time -= tm->tm_hour * USECS_PER_HOUR;
    1504        6238 :     tm->tm_min = time / USECS_PER_MINUTE;
    1505        6238 :     time -= tm->tm_min * USECS_PER_MINUTE;
    1506        6238 :     tm->tm_sec = time / USECS_PER_SEC;
    1507        6238 :     time -= tm->tm_sec * USECS_PER_SEC;
    1508        6238 :     *fsec = time;
    1509        6238 :     return 0;
    1510             : }
    1511             : 
    1512             : Datum
    1513        5596 : time_out(PG_FUNCTION_ARGS)
    1514             : {
    1515        5596 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    1516             :     char       *result;
    1517             :     struct pg_tm tt,
    1518        5596 :                *tm = &tt;
    1519             :     fsec_t      fsec;
    1520             :     char        buf[MAXDATELEN + 1];
    1521             : 
    1522        5596 :     time2tm(time, tm, &fsec);
    1523        5596 :     EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
    1524             : 
    1525        5596 :     result = pstrdup(buf);
    1526        5596 :     PG_RETURN_CSTRING(result);
    1527             : }
    1528             : 
    1529             : /*
    1530             :  *      time_recv           - converts external binary format to time
    1531             :  */
    1532             : Datum
    1533           0 : time_recv(PG_FUNCTION_ARGS)
    1534             : {
    1535           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    1536             : 
    1537             : #ifdef NOT_USED
    1538             :     Oid         typelem = PG_GETARG_OID(1);
    1539             : #endif
    1540           0 :     int32       typmod = PG_GETARG_INT32(2);
    1541             :     TimeADT     result;
    1542             : 
    1543           0 :     result = pq_getmsgint64(buf);
    1544             : 
    1545           0 :     if (result < INT64CONST(0) || result > USECS_PER_DAY)
    1546           0 :         ereport(ERROR,
    1547             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1548             :                  errmsg("time out of range")));
    1549             : 
    1550           0 :     AdjustTimeForTypmod(&result, typmod);
    1551             : 
    1552           0 :     PG_RETURN_TIMEADT(result);
    1553             : }
    1554             : 
    1555             : /*
    1556             :  *      time_send           - converts time to binary format
    1557             :  */
    1558             : Datum
    1559           0 : time_send(PG_FUNCTION_ARGS)
    1560             : {
    1561           0 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    1562             :     StringInfoData buf;
    1563             : 
    1564           0 :     pq_begintypsend(&buf);
    1565           0 :     pq_sendint64(&buf, time);
    1566           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1567             : }
    1568             : 
    1569             : Datum
    1570          22 : timetypmodin(PG_FUNCTION_ARGS)
    1571             : {
    1572          22 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
    1573             : 
    1574          22 :     PG_RETURN_INT32(anytime_typmodin(false, ta));
    1575             : }
    1576             : 
    1577             : Datum
    1578          10 : timetypmodout(PG_FUNCTION_ARGS)
    1579             : {
    1580          10 :     int32       typmod = PG_GETARG_INT32(0);
    1581             : 
    1582          10 :     PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
    1583             : }
    1584             : 
    1585             : /*
    1586             :  *      make_time           - time constructor
    1587             :  */
    1588             : Datum
    1589          18 : make_time(PG_FUNCTION_ARGS)
    1590             : {
    1591          18 :     int         tm_hour = PG_GETARG_INT32(0);
    1592          18 :     int         tm_min = PG_GETARG_INT32(1);
    1593          18 :     double      sec = PG_GETARG_FLOAT8(2);
    1594             :     TimeADT     time;
    1595             : 
    1596             :     /* Check for time overflow */
    1597          18 :     if (float_time_overflows(tm_hour, tm_min, sec))
    1598          12 :         ereport(ERROR,
    1599             :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
    1600             :                  errmsg("time field value out of range: %d:%02d:%02g",
    1601             :                         tm_hour, tm_min, sec)));
    1602             : 
    1603             :     /* This should match tm2time */
    1604           6 :     time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
    1605           6 :             * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
    1606             : 
    1607           6 :     PG_RETURN_TIMEADT(time);
    1608             : }
    1609             : 
    1610             : 
    1611             : /* time_support()
    1612             :  *
    1613             :  * Planner support function for the time_scale() and timetz_scale()
    1614             :  * length coercion functions (we need not distinguish them here).
    1615             :  */
    1616             : Datum
    1617          24 : time_support(PG_FUNCTION_ARGS)
    1618             : {
    1619          24 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
    1620          24 :     Node       *ret = NULL;
    1621             : 
    1622          24 :     if (IsA(rawreq, SupportRequestSimplify))
    1623             :     {
    1624          12 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
    1625             : 
    1626          12 :         ret = TemporalSimplify(MAX_TIME_PRECISION, (Node *) req->fcall);
    1627             :     }
    1628             : 
    1629          24 :     PG_RETURN_POINTER(ret);
    1630             : }
    1631             : 
    1632             : /* time_scale()
    1633             :  * Adjust time type for specified scale factor.
    1634             :  * Used by PostgreSQL type system to stuff columns.
    1635             :  */
    1636             : Datum
    1637          66 : time_scale(PG_FUNCTION_ARGS)
    1638             : {
    1639          66 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    1640          66 :     int32       typmod = PG_GETARG_INT32(1);
    1641             :     TimeADT     result;
    1642             : 
    1643          66 :     result = time;
    1644          66 :     AdjustTimeForTypmod(&result, typmod);
    1645             : 
    1646          66 :     PG_RETURN_TIMEADT(result);
    1647             : }
    1648             : 
    1649             : /* AdjustTimeForTypmod()
    1650             :  * Force the precision of the time value to a specified value.
    1651             :  * Uses *exactly* the same code as in AdjustTimestampForTypmod()
    1652             :  * but we make a separate copy because those types do not
    1653             :  * have a fundamental tie together but rather a coincidence of
    1654             :  * implementation. - thomas
    1655             :  */
    1656             : void
    1657        7816 : AdjustTimeForTypmod(TimeADT *time, int32 typmod)
    1658             : {
    1659             :     static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
    1660             :         INT64CONST(1000000),
    1661             :         INT64CONST(100000),
    1662             :         INT64CONST(10000),
    1663             :         INT64CONST(1000),
    1664             :         INT64CONST(100),
    1665             :         INT64CONST(10),
    1666             :         INT64CONST(1)
    1667             :     };
    1668             : 
    1669             :     static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
    1670             :         INT64CONST(500000),
    1671             :         INT64CONST(50000),
    1672             :         INT64CONST(5000),
    1673             :         INT64CONST(500),
    1674             :         INT64CONST(50),
    1675             :         INT64CONST(5),
    1676             :         INT64CONST(0)
    1677             :     };
    1678             : 
    1679        7816 :     if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
    1680             :     {
    1681         528 :         if (*time >= INT64CONST(0))
    1682         528 :             *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
    1683         528 :                 TimeScales[typmod];
    1684             :         else
    1685           0 :             *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
    1686           0 :                       TimeScales[typmod]);
    1687             :     }
    1688        7816 : }
    1689             : 
    1690             : 
    1691             : Datum
    1692        9518 : time_eq(PG_FUNCTION_ARGS)
    1693             : {
    1694        9518 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1695        9518 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1696             : 
    1697        9518 :     PG_RETURN_BOOL(time1 == time2);
    1698             : }
    1699             : 
    1700             : Datum
    1701           0 : time_ne(PG_FUNCTION_ARGS)
    1702             : {
    1703           0 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1704           0 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1705             : 
    1706           0 :     PG_RETURN_BOOL(time1 != time2);
    1707             : }
    1708             : 
    1709             : Datum
    1710       22970 : time_lt(PG_FUNCTION_ARGS)
    1711             : {
    1712       22970 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1713       22970 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1714             : 
    1715       22970 :     PG_RETURN_BOOL(time1 < time2);
    1716             : }
    1717             : 
    1718             : Datum
    1719        8724 : time_le(PG_FUNCTION_ARGS)
    1720             : {
    1721        8724 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1722        8724 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1723             : 
    1724        8724 :     PG_RETURN_BOOL(time1 <= time2);
    1725             : }
    1726             : 
    1727             : Datum
    1728       11964 : time_gt(PG_FUNCTION_ARGS)
    1729             : {
    1730       11964 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1731       11964 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1732             : 
    1733       11964 :     PG_RETURN_BOOL(time1 > time2);
    1734             : }
    1735             : 
    1736             : Datum
    1737        6894 : time_ge(PG_FUNCTION_ARGS)
    1738             : {
    1739        6894 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1740        6894 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1741             : 
    1742        6894 :     PG_RETURN_BOOL(time1 >= time2);
    1743             : }
    1744             : 
    1745             : Datum
    1746       23390 : time_cmp(PG_FUNCTION_ARGS)
    1747             : {
    1748       23390 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1749       23390 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1750             : 
    1751       23390 :     if (time1 < time2)
    1752       10858 :         PG_RETURN_INT32(-1);
    1753       12532 :     if (time1 > time2)
    1754       10202 :         PG_RETURN_INT32(1);
    1755        2330 :     PG_RETURN_INT32(0);
    1756             : }
    1757             : 
    1758             : Datum
    1759        2262 : time_hash(PG_FUNCTION_ARGS)
    1760             : {
    1761        2262 :     return hashint8(fcinfo);
    1762             : }
    1763             : 
    1764             : Datum
    1765          60 : time_hash_extended(PG_FUNCTION_ARGS)
    1766             : {
    1767          60 :     return hashint8extended(fcinfo);
    1768             : }
    1769             : 
    1770             : Datum
    1771           0 : time_larger(PG_FUNCTION_ARGS)
    1772             : {
    1773           0 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1774           0 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1775             : 
    1776           0 :     PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
    1777             : }
    1778             : 
    1779             : Datum
    1780           0 : time_smaller(PG_FUNCTION_ARGS)
    1781             : {
    1782           0 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    1783           0 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    1784             : 
    1785           0 :     PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
    1786             : }
    1787             : 
    1788             : /* overlaps_time() --- implements the SQL OVERLAPS operator.
    1789             :  *
    1790             :  * Algorithm is per SQL spec.  This is much harder than you'd think
    1791             :  * because the spec requires us to deliver a non-null answer in some cases
    1792             :  * where some of the inputs are null.
    1793             :  */
    1794             : Datum
    1795          24 : overlaps_time(PG_FUNCTION_ARGS)
    1796             : {
    1797             :     /*
    1798             :      * The arguments are TimeADT, but we leave them as generic Datums to avoid
    1799             :      * dereferencing nulls (TimeADT is pass-by-reference!)
    1800             :      */
    1801          24 :     Datum       ts1 = PG_GETARG_DATUM(0);
    1802          24 :     Datum       te1 = PG_GETARG_DATUM(1);
    1803          24 :     Datum       ts2 = PG_GETARG_DATUM(2);
    1804          24 :     Datum       te2 = PG_GETARG_DATUM(3);
    1805          24 :     bool        ts1IsNull = PG_ARGISNULL(0);
    1806          24 :     bool        te1IsNull = PG_ARGISNULL(1);
    1807          24 :     bool        ts2IsNull = PG_ARGISNULL(2);
    1808          24 :     bool        te2IsNull = PG_ARGISNULL(3);
    1809             : 
    1810             : #define TIMEADT_GT(t1,t2) \
    1811             :     (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
    1812             : #define TIMEADT_LT(t1,t2) \
    1813             :     (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
    1814             : 
    1815             :     /*
    1816             :      * If both endpoints of interval 1 are null, the result is null (unknown).
    1817             :      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
    1818             :      * take ts1 as the lesser endpoint.
    1819             :      */
    1820          24 :     if (ts1IsNull)
    1821             :     {
    1822           0 :         if (te1IsNull)
    1823           0 :             PG_RETURN_NULL();
    1824             :         /* swap null for non-null */
    1825           0 :         ts1 = te1;
    1826           0 :         te1IsNull = true;
    1827             :     }
    1828          24 :     else if (!te1IsNull)
    1829             :     {
    1830          24 :         if (TIMEADT_GT(ts1, te1))
    1831             :         {
    1832           0 :             Datum       tt = ts1;
    1833             : 
    1834           0 :             ts1 = te1;
    1835           0 :             te1 = tt;
    1836             :         }
    1837             :     }
    1838             : 
    1839             :     /* Likewise for interval 2. */
    1840          24 :     if (ts2IsNull)
    1841             :     {
    1842           0 :         if (te2IsNull)
    1843           0 :             PG_RETURN_NULL();
    1844             :         /* swap null for non-null */
    1845           0 :         ts2 = te2;
    1846           0 :         te2IsNull = true;
    1847             :     }
    1848          24 :     else if (!te2IsNull)
    1849             :     {
    1850          24 :         if (TIMEADT_GT(ts2, te2))
    1851             :         {
    1852           0 :             Datum       tt = ts2;
    1853             : 
    1854           0 :             ts2 = te2;
    1855           0 :             te2 = tt;
    1856             :         }
    1857             :     }
    1858             : 
    1859             :     /*
    1860             :      * At this point neither ts1 nor ts2 is null, so we can consider three
    1861             :      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
    1862             :      */
    1863          24 :     if (TIMEADT_GT(ts1, ts2))
    1864             :     {
    1865             :         /*
    1866             :          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
    1867             :          * in the presence of nulls it's not quite completely so.
    1868             :          */
    1869           0 :         if (te2IsNull)
    1870           0 :             PG_RETURN_NULL();
    1871           0 :         if (TIMEADT_LT(ts1, te2))
    1872           0 :             PG_RETURN_BOOL(true);
    1873           0 :         if (te1IsNull)
    1874           0 :             PG_RETURN_NULL();
    1875             : 
    1876             :         /*
    1877             :          * If te1 is not null then we had ts1 <= te1 above, and we just found
    1878             :          * ts1 >= te2, hence te1 >= te2.
    1879             :          */
    1880           0 :         PG_RETURN_BOOL(false);
    1881             :     }
    1882          24 :     else if (TIMEADT_LT(ts1, ts2))
    1883             :     {
    1884             :         /* This case is ts2 < te1 OR te2 < te1 */
    1885          24 :         if (te1IsNull)
    1886           0 :             PG_RETURN_NULL();
    1887          24 :         if (TIMEADT_LT(ts2, te1))
    1888          12 :             PG_RETURN_BOOL(true);
    1889          12 :         if (te2IsNull)
    1890           0 :             PG_RETURN_NULL();
    1891             : 
    1892             :         /*
    1893             :          * If te2 is not null then we had ts2 <= te2 above, and we just found
    1894             :          * ts2 >= te1, hence te2 >= te1.
    1895             :          */
    1896          12 :         PG_RETURN_BOOL(false);
    1897             :     }
    1898             :     else
    1899             :     {
    1900             :         /*
    1901             :          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
    1902             :          * rather silly way of saying "true if both are nonnull, else null".
    1903             :          */
    1904           0 :         if (te1IsNull || te2IsNull)
    1905           0 :             PG_RETURN_NULL();
    1906           0 :         PG_RETURN_BOOL(true);
    1907             :     }
    1908             : 
    1909             : #undef TIMEADT_GT
    1910             : #undef TIMEADT_LT
    1911             : }
    1912             : 
    1913             : /* timestamp_time()
    1914             :  * Convert timestamp to time data type.
    1915             :  */
    1916             : Datum
    1917          36 : timestamp_time(PG_FUNCTION_ARGS)
    1918             : {
    1919          36 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    1920             :     TimeADT     result;
    1921             :     struct pg_tm tt,
    1922          36 :                *tm = &tt;
    1923             :     fsec_t      fsec;
    1924             : 
    1925          36 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    1926           0 :         PG_RETURN_NULL();
    1927             : 
    1928          36 :     if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    1929           0 :         ereport(ERROR,
    1930             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1931             :                  errmsg("timestamp out of range")));
    1932             : 
    1933             :     /*
    1934             :      * Could also do this with time = (timestamp / USECS_PER_DAY *
    1935             :      * USECS_PER_DAY) - timestamp;
    1936             :      */
    1937          36 :     result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
    1938          36 :               USECS_PER_SEC) + fsec;
    1939             : 
    1940          36 :     PG_RETURN_TIMEADT(result);
    1941             : }
    1942             : 
    1943             : /* timestamptz_time()
    1944             :  * Convert timestamptz to time data type.
    1945             :  */
    1946             : Datum
    1947          54 : timestamptz_time(PG_FUNCTION_ARGS)
    1948             : {
    1949          54 :     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
    1950             :     TimeADT     result;
    1951             :     struct pg_tm tt,
    1952          54 :                *tm = &tt;
    1953             :     int         tz;
    1954             :     fsec_t      fsec;
    1955             : 
    1956          54 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    1957           0 :         PG_RETURN_NULL();
    1958             : 
    1959          54 :     if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    1960           0 :         ereport(ERROR,
    1961             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1962             :                  errmsg("timestamp out of range")));
    1963             : 
    1964             :     /*
    1965             :      * Could also do this with time = (timestamp / USECS_PER_DAY *
    1966             :      * USECS_PER_DAY) - timestamp;
    1967             :      */
    1968          54 :     result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
    1969          54 :               USECS_PER_SEC) + fsec;
    1970             : 
    1971          54 :     PG_RETURN_TIMEADT(result);
    1972             : }
    1973             : 
    1974             : /* datetime_timestamp()
    1975             :  * Convert date and time to timestamp data type.
    1976             :  */
    1977             : Datum
    1978          30 : datetime_timestamp(PG_FUNCTION_ARGS)
    1979             : {
    1980          30 :     DateADT     date = PG_GETARG_DATEADT(0);
    1981          30 :     TimeADT     time = PG_GETARG_TIMEADT(1);
    1982             :     Timestamp   result;
    1983             : 
    1984          30 :     result = date2timestamp(date);
    1985          30 :     if (!TIMESTAMP_NOT_FINITE(result))
    1986             :     {
    1987          30 :         result += time;
    1988          30 :         if (!IS_VALID_TIMESTAMP(result))
    1989           0 :             ereport(ERROR,
    1990             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1991             :                      errmsg("timestamp out of range")));
    1992             :     }
    1993             : 
    1994          30 :     PG_RETURN_TIMESTAMP(result);
    1995             : }
    1996             : 
    1997             : /* time_interval()
    1998             :  * Convert time to interval data type.
    1999             :  */
    2000             : Datum
    2001          12 : time_interval(PG_FUNCTION_ARGS)
    2002             : {
    2003          12 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    2004             :     Interval   *result;
    2005             : 
    2006          12 :     result = (Interval *) palloc(sizeof(Interval));
    2007             : 
    2008          12 :     result->time = time;
    2009          12 :     result->day = 0;
    2010          12 :     result->month = 0;
    2011             : 
    2012          12 :     PG_RETURN_INTERVAL_P(result);
    2013             : }
    2014             : 
    2015             : /* interval_time()
    2016             :  * Convert interval to time data type.
    2017             :  *
    2018             :  * This is defined as producing the fractional-day portion of the interval.
    2019             :  * Therefore, we can just ignore the months field.  It is not real clear
    2020             :  * what to do with negative intervals, but we choose to subtract the floor,
    2021             :  * so that, say, '-2 hours' becomes '22:00:00'.
    2022             :  */
    2023             : Datum
    2024          30 : interval_time(PG_FUNCTION_ARGS)
    2025             : {
    2026          30 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    2027             :     TimeADT     result;
    2028             : 
    2029          30 :     if (INTERVAL_NOT_FINITE(span))
    2030          12 :         ereport(ERROR,
    2031             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2032             :                  errmsg("cannot convert infinite interval to time")));
    2033             : 
    2034          18 :     result = span->time % USECS_PER_DAY;
    2035          18 :     if (result < 0)
    2036           6 :         result += USECS_PER_DAY;
    2037             : 
    2038          18 :     PG_RETURN_TIMEADT(result);
    2039             : }
    2040             : 
    2041             : /* time_mi_time()
    2042             :  * Subtract two times to produce an interval.
    2043             :  */
    2044             : Datum
    2045        6560 : time_mi_time(PG_FUNCTION_ARGS)
    2046             : {
    2047        6560 :     TimeADT     time1 = PG_GETARG_TIMEADT(0);
    2048        6560 :     TimeADT     time2 = PG_GETARG_TIMEADT(1);
    2049             :     Interval   *result;
    2050             : 
    2051        6560 :     result = (Interval *) palloc(sizeof(Interval));
    2052             : 
    2053        6560 :     result->month = 0;
    2054        6560 :     result->day = 0;
    2055        6560 :     result->time = time1 - time2;
    2056             : 
    2057        6560 :     PG_RETURN_INTERVAL_P(result);
    2058             : }
    2059             : 
    2060             : /* time_pl_interval()
    2061             :  * Add interval to time.
    2062             :  */
    2063             : Datum
    2064        2646 : time_pl_interval(PG_FUNCTION_ARGS)
    2065             : {
    2066        2646 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    2067        2646 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2068             :     TimeADT     result;
    2069             : 
    2070        2646 :     if (INTERVAL_NOT_FINITE(span))
    2071          12 :         ereport(ERROR,
    2072             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2073             :                  errmsg("cannot add infinite interval to time")));
    2074             : 
    2075        2634 :     result = time + span->time;
    2076        2634 :     result -= result / USECS_PER_DAY * USECS_PER_DAY;
    2077        2634 :     if (result < INT64CONST(0))
    2078           6 :         result += USECS_PER_DAY;
    2079             : 
    2080        2634 :     PG_RETURN_TIMEADT(result);
    2081             : }
    2082             : 
    2083             : /* time_mi_interval()
    2084             :  * Subtract interval from time.
    2085             :  */
    2086             : Datum
    2087         618 : time_mi_interval(PG_FUNCTION_ARGS)
    2088             : {
    2089         618 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    2090         618 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2091             :     TimeADT     result;
    2092             : 
    2093         618 :     if (INTERVAL_NOT_FINITE(span))
    2094          12 :         ereport(ERROR,
    2095             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2096             :                  errmsg("cannot subtract infinite interval from time")));
    2097             : 
    2098         606 :     result = time - span->time;
    2099         606 :     result -= result / USECS_PER_DAY * USECS_PER_DAY;
    2100         606 :     if (result < INT64CONST(0))
    2101          72 :         result += USECS_PER_DAY;
    2102             : 
    2103         606 :     PG_RETURN_TIMEADT(result);
    2104             : }
    2105             : 
    2106             : /*
    2107             :  * in_range support function for time.
    2108             :  */
    2109             : Datum
    2110         960 : in_range_time_interval(PG_FUNCTION_ARGS)
    2111             : {
    2112         960 :     TimeADT     val = PG_GETARG_TIMEADT(0);
    2113         960 :     TimeADT     base = PG_GETARG_TIMEADT(1);
    2114         960 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    2115         960 :     bool        sub = PG_GETARG_BOOL(3);
    2116         960 :     bool        less = PG_GETARG_BOOL(4);
    2117             :     TimeADT     sum;
    2118             : 
    2119             :     /*
    2120             :      * Like time_pl_interval/time_mi_interval, we disregard the month and day
    2121             :      * fields of the offset.  So our test for negative should too.  This also
    2122             :      * catches -infinity, so we only need worry about +infinity below.
    2123             :      */
    2124         960 :     if (offset->time < 0)
    2125          12 :         ereport(ERROR,
    2126             :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    2127             :                  errmsg("invalid preceding or following size in window function")));
    2128             : 
    2129             :     /*
    2130             :      * We can't use time_pl_interval/time_mi_interval here, because their
    2131             :      * wraparound behavior would give wrong (or at least undesirable) answers.
    2132             :      * Fortunately the equivalent non-wrapping behavior is trivial, except
    2133             :      * that adding an infinite (or very large) interval might cause integer
    2134             :      * overflow.  Subtraction cannot overflow here.
    2135             :      */
    2136         948 :     if (sub)
    2137         474 :         sum = base - offset->time;
    2138         474 :     else if (pg_add_s64_overflow(base, offset->time, &sum))
    2139         216 :         PG_RETURN_BOOL(less);
    2140             : 
    2141         732 :     if (less)
    2142         330 :         PG_RETURN_BOOL(val <= sum);
    2143             :     else
    2144         402 :         PG_RETURN_BOOL(val >= sum);
    2145             : }
    2146             : 
    2147             : 
    2148             : /* time_part() and extract_time()
    2149             :  * Extract specified field from time type.
    2150             :  */
    2151             : static Datum
    2152          78 : time_part_common(PG_FUNCTION_ARGS, bool retnumeric)
    2153             : {
    2154          78 :     text       *units = PG_GETARG_TEXT_PP(0);
    2155          78 :     TimeADT     time = PG_GETARG_TIMEADT(1);
    2156             :     int64       intresult;
    2157             :     int         type,
    2158             :                 val;
    2159             :     char       *lowunits;
    2160             : 
    2161          78 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    2162          78 :                                             VARSIZE_ANY_EXHDR(units),
    2163             :                                             false);
    2164             : 
    2165          78 :     type = DecodeUnits(0, lowunits, &val);
    2166          78 :     if (type == UNKNOWN_FIELD)
    2167          18 :         type = DecodeSpecial(0, lowunits, &val);
    2168             : 
    2169          78 :     if (type == UNITS)
    2170             :     {
    2171             :         fsec_t      fsec;
    2172             :         struct pg_tm tt,
    2173          60 :                    *tm = &tt;
    2174             : 
    2175          60 :         time2tm(time, tm, &fsec);
    2176             : 
    2177          60 :         switch (val)
    2178             :         {
    2179          12 :             case DTK_MICROSEC:
    2180          12 :                 intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
    2181          12 :                 break;
    2182             : 
    2183          12 :             case DTK_MILLISEC:
    2184          12 :                 if (retnumeric)
    2185             :                     /*---
    2186             :                      * tm->tm_sec * 1000 + fsec / 1000
    2187             :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1000
    2188             :                      */
    2189          24 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
    2190             :                 else
    2191           6 :                     PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
    2192             :                 break;
    2193             : 
    2194          12 :             case DTK_SECOND:
    2195          12 :                 if (retnumeric)
    2196             :                     /*---
    2197             :                      * tm->tm_sec + fsec / 1'000'000
    2198             :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
    2199             :                      */
    2200           6 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
    2201             :                 else
    2202           6 :                     PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
    2203             :                 break;
    2204             : 
    2205           6 :             case DTK_MINUTE:
    2206           6 :                 intresult = tm->tm_min;
    2207           6 :                 break;
    2208             : 
    2209           6 :             case DTK_HOUR:
    2210           6 :                 intresult = tm->tm_hour;
    2211           6 :                 break;
    2212             : 
    2213          12 :             case DTK_TZ:
    2214             :             case DTK_TZ_MINUTE:
    2215             :             case DTK_TZ_HOUR:
    2216             :             case DTK_DAY:
    2217             :             case DTK_MONTH:
    2218             :             case DTK_QUARTER:
    2219             :             case DTK_YEAR:
    2220             :             case DTK_DECADE:
    2221             :             case DTK_CENTURY:
    2222             :             case DTK_MILLENNIUM:
    2223             :             case DTK_ISOYEAR:
    2224             :             default:
    2225          12 :                 ereport(ERROR,
    2226             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2227             :                          errmsg("unit \"%s\" not supported for type %s",
    2228             :                                 lowunits, format_type_be(TIMEOID))));
    2229             :                 intresult = 0;
    2230             :         }
    2231             :     }
    2232          18 :     else if (type == RESERV && val == DTK_EPOCH)
    2233             :     {
    2234          12 :         if (retnumeric)
    2235           6 :             PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time, 6));
    2236             :         else
    2237           6 :             PG_RETURN_FLOAT8(time / 1000000.0);
    2238             :     }
    2239             :     else
    2240             :     {
    2241           6 :         ereport(ERROR,
    2242             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2243             :                  errmsg("unit \"%s\" not recognized for type %s",
    2244             :                         lowunits, format_type_be(TIMEOID))));
    2245             :         intresult = 0;
    2246             :     }
    2247             : 
    2248          24 :     if (retnumeric)
    2249          18 :         PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    2250             :     else
    2251           6 :         PG_RETURN_FLOAT8(intresult);
    2252             : }
    2253             : 
    2254             : Datum
    2255          24 : time_part(PG_FUNCTION_ARGS)
    2256             : {
    2257          24 :     return time_part_common(fcinfo, false);
    2258             : }
    2259             : 
    2260             : Datum
    2261          54 : extract_time(PG_FUNCTION_ARGS)
    2262             : {
    2263          54 :     return time_part_common(fcinfo, true);
    2264             : }
    2265             : 
    2266             : 
    2267             : /*****************************************************************************
    2268             :  *   Time With Time Zone ADT
    2269             :  *****************************************************************************/
    2270             : 
    2271             : /* tm2timetz()
    2272             :  * Convert a tm structure to a time data type.
    2273             :  */
    2274             : int
    2275        3916 : tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
    2276             : {
    2277        3916 :     result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
    2278        3916 :                     USECS_PER_SEC) + fsec;
    2279        3916 :     result->zone = tz;
    2280             : 
    2281        3916 :     return 0;
    2282             : }
    2283             : 
    2284             : Datum
    2285        2140 : timetz_in(PG_FUNCTION_ARGS)
    2286             : {
    2287        2140 :     char       *str = PG_GETARG_CSTRING(0);
    2288             : #ifdef NOT_USED
    2289             :     Oid         typelem = PG_GETARG_OID(1);
    2290             : #endif
    2291        2140 :     int32       typmod = PG_GETARG_INT32(2);
    2292        2140 :     Node       *escontext = fcinfo->context;
    2293             :     TimeTzADT  *result;
    2294             :     fsec_t      fsec;
    2295             :     struct pg_tm tt,
    2296        2140 :                *tm = &tt;
    2297             :     int         tz;
    2298             :     int         nf;
    2299             :     int         dterr;
    2300             :     char        workbuf[MAXDATELEN + 1];
    2301             :     char       *field[MAXDATEFIELDS];
    2302             :     int         dtype;
    2303             :     int         ftype[MAXDATEFIELDS];
    2304             :     DateTimeErrorExtra extra;
    2305             : 
    2306        2140 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
    2307             :                           field, ftype, MAXDATEFIELDS, &nf);
    2308        2140 :     if (dterr == 0)
    2309        2140 :         dterr = DecodeTimeOnly(field, ftype, nf,
    2310             :                                &dtype, tm, &fsec, &tz, &extra);
    2311        2140 :     if (dterr != 0)
    2312             :     {
    2313          78 :         DateTimeParseError(dterr, &extra, str, "time with time zone",
    2314             :                            escontext);
    2315          24 :         PG_RETURN_NULL();
    2316             :     }
    2317             : 
    2318        2062 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2319        2062 :     tm2timetz(tm, fsec, tz, result);
    2320        2062 :     AdjustTimeForTypmod(&(result->time), typmod);
    2321             : 
    2322        2062 :     PG_RETURN_TIMETZADT_P(result);
    2323             : }
    2324             : 
    2325             : Datum
    2326        6392 : timetz_out(PG_FUNCTION_ARGS)
    2327             : {
    2328        6392 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
    2329             :     char       *result;
    2330             :     struct pg_tm tt,
    2331        6392 :                *tm = &tt;
    2332             :     fsec_t      fsec;
    2333             :     int         tz;
    2334             :     char        buf[MAXDATELEN + 1];
    2335             : 
    2336        6392 :     timetz2tm(time, tm, &fsec, &tz);
    2337        6392 :     EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
    2338             : 
    2339        6392 :     result = pstrdup(buf);
    2340        6392 :     PG_RETURN_CSTRING(result);
    2341             : }
    2342             : 
    2343             : /*
    2344             :  *      timetz_recv         - converts external binary format to timetz
    2345             :  */
    2346             : Datum
    2347           0 : timetz_recv(PG_FUNCTION_ARGS)
    2348             : {
    2349           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    2350             : 
    2351             : #ifdef NOT_USED
    2352             :     Oid         typelem = PG_GETARG_OID(1);
    2353             : #endif
    2354           0 :     int32       typmod = PG_GETARG_INT32(2);
    2355             :     TimeTzADT  *result;
    2356             : 
    2357           0 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2358             : 
    2359           0 :     result->time = pq_getmsgint64(buf);
    2360             : 
    2361           0 :     if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
    2362           0 :         ereport(ERROR,
    2363             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2364             :                  errmsg("time out of range")));
    2365             : 
    2366           0 :     result->zone = pq_getmsgint(buf, sizeof(result->zone));
    2367             : 
    2368             :     /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
    2369           0 :     if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
    2370           0 :         ereport(ERROR,
    2371             :                 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
    2372             :                  errmsg("time zone displacement out of range")));
    2373             : 
    2374           0 :     AdjustTimeForTypmod(&(result->time), typmod);
    2375             : 
    2376           0 :     PG_RETURN_TIMETZADT_P(result);
    2377             : }
    2378             : 
    2379             : /*
    2380             :  *      timetz_send         - converts timetz to binary format
    2381             :  */
    2382             : Datum
    2383           0 : timetz_send(PG_FUNCTION_ARGS)
    2384             : {
    2385           0 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
    2386             :     StringInfoData buf;
    2387             : 
    2388           0 :     pq_begintypsend(&buf);
    2389           0 :     pq_sendint64(&buf, time->time);
    2390           0 :     pq_sendint32(&buf, time->zone);
    2391           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    2392             : }
    2393             : 
    2394             : Datum
    2395          22 : timetztypmodin(PG_FUNCTION_ARGS)
    2396             : {
    2397          22 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
    2398             : 
    2399          22 :     PG_RETURN_INT32(anytime_typmodin(true, ta));
    2400             : }
    2401             : 
    2402             : Datum
    2403          10 : timetztypmodout(PG_FUNCTION_ARGS)
    2404             : {
    2405          10 :     int32       typmod = PG_GETARG_INT32(0);
    2406             : 
    2407          10 :     PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
    2408             : }
    2409             : 
    2410             : 
    2411             : /* timetz2tm()
    2412             :  * Convert TIME WITH TIME ZONE data type to POSIX time structure.
    2413             :  */
    2414             : int
    2415        6806 : timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
    2416             : {
    2417        6806 :     TimeOffset  trem = time->time;
    2418             : 
    2419        6806 :     tm->tm_hour = trem / USECS_PER_HOUR;
    2420        6806 :     trem -= tm->tm_hour * USECS_PER_HOUR;
    2421        6806 :     tm->tm_min = trem / USECS_PER_MINUTE;
    2422        6806 :     trem -= tm->tm_min * USECS_PER_MINUTE;
    2423        6806 :     tm->tm_sec = trem / USECS_PER_SEC;
    2424        6806 :     *fsec = trem - tm->tm_sec * USECS_PER_SEC;
    2425             : 
    2426        6806 :     if (tzp != NULL)
    2427        6806 :         *tzp = time->zone;
    2428             : 
    2429        6806 :     return 0;
    2430             : }
    2431             : 
    2432             : /* timetz_scale()
    2433             :  * Adjust time type for specified scale factor.
    2434             :  * Used by PostgreSQL type system to stuff columns.
    2435             :  */
    2436             : Datum
    2437          78 : timetz_scale(PG_FUNCTION_ARGS)
    2438             : {
    2439          78 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
    2440          78 :     int32       typmod = PG_GETARG_INT32(1);
    2441             :     TimeTzADT  *result;
    2442             : 
    2443          78 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2444             : 
    2445          78 :     result->time = time->time;
    2446          78 :     result->zone = time->zone;
    2447             : 
    2448          78 :     AdjustTimeForTypmod(&(result->time), typmod);
    2449             : 
    2450          78 :     PG_RETURN_TIMETZADT_P(result);
    2451             : }
    2452             : 
    2453             : 
    2454             : static int
    2455       61768 : timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
    2456             : {
    2457             :     TimeOffset  t1,
    2458             :                 t2;
    2459             : 
    2460             :     /* Primary sort is by true (GMT-equivalent) time */
    2461       61768 :     t1 = time1->time + (time1->zone * USECS_PER_SEC);
    2462       61768 :     t2 = time2->time + (time2->zone * USECS_PER_SEC);
    2463             : 
    2464       61768 :     if (t1 > t2)
    2465       27160 :         return 1;
    2466       34608 :     if (t1 < t2)
    2467       26206 :         return -1;
    2468             : 
    2469             :     /*
    2470             :      * If same GMT time, sort by timezone; we only want to say that two
    2471             :      * timetz's are equal if both the time and zone parts are equal.
    2472             :      */
    2473        8402 :     if (time1->zone > time2->zone)
    2474          78 :         return 1;
    2475        8324 :     if (time1->zone < time2->zone)
    2476          36 :         return -1;
    2477             : 
    2478        8288 :     return 0;
    2479             : }
    2480             : 
    2481             : Datum
    2482        7942 : timetz_eq(PG_FUNCTION_ARGS)
    2483             : {
    2484        7942 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2485        7942 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2486             : 
    2487        7942 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
    2488             : }
    2489             : 
    2490             : Datum
    2491           0 : timetz_ne(PG_FUNCTION_ARGS)
    2492             : {
    2493           0 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2494           0 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2495             : 
    2496           0 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
    2497             : }
    2498             : 
    2499             : Datum
    2500       19646 : timetz_lt(PG_FUNCTION_ARGS)
    2501             : {
    2502       19646 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2503       19646 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2504             : 
    2505       19646 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
    2506             : }
    2507             : 
    2508             : Datum
    2509        8452 : timetz_le(PG_FUNCTION_ARGS)
    2510             : {
    2511        8452 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2512        8452 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2513             : 
    2514        8452 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
    2515             : }
    2516             : 
    2517             : Datum
    2518        9434 : timetz_gt(PG_FUNCTION_ARGS)
    2519             : {
    2520        9434 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2521        9434 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2522             : 
    2523        9434 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
    2524             : }
    2525             : 
    2526             : Datum
    2527        8356 : timetz_ge(PG_FUNCTION_ARGS)
    2528             : {
    2529        8356 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2530        8356 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2531             : 
    2532        8356 :     PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
    2533             : }
    2534             : 
    2535             : Datum
    2536        7200 : timetz_cmp(PG_FUNCTION_ARGS)
    2537             : {
    2538        7200 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2539        7200 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2540             : 
    2541        7200 :     PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
    2542             : }
    2543             : 
    2544             : Datum
    2545        2262 : timetz_hash(PG_FUNCTION_ARGS)
    2546             : {
    2547        2262 :     TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
    2548             :     uint32      thash;
    2549             : 
    2550             :     /*
    2551             :      * To avoid any problems with padding bytes in the struct, we figure the
    2552             :      * field hashes separately and XOR them.
    2553             :      */
    2554        2262 :     thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
    2555             :                                                Int64GetDatumFast(key->time)));
    2556        2262 :     thash ^= DatumGetUInt32(hash_uint32(key->zone));
    2557        2262 :     PG_RETURN_UINT32(thash);
    2558             : }
    2559             : 
    2560             : Datum
    2561          60 : timetz_hash_extended(PG_FUNCTION_ARGS)
    2562             : {
    2563          60 :     TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
    2564          60 :     Datum       seed = PG_GETARG_DATUM(1);
    2565             :     uint64      thash;
    2566             : 
    2567             :     /* Same approach as timetz_hash */
    2568          60 :     thash = DatumGetUInt64(DirectFunctionCall2(hashint8extended,
    2569             :                                                Int64GetDatumFast(key->time),
    2570             :                                                seed));
    2571          60 :     thash ^= DatumGetUInt64(hash_uint32_extended(key->zone,
    2572          60 :                                                  DatumGetInt64(seed)));
    2573          60 :     PG_RETURN_UINT64(thash);
    2574             : }
    2575             : 
    2576             : Datum
    2577           0 : timetz_larger(PG_FUNCTION_ARGS)
    2578             : {
    2579           0 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2580           0 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2581             :     TimeTzADT  *result;
    2582             : 
    2583           0 :     if (timetz_cmp_internal(time1, time2) > 0)
    2584           0 :         result = time1;
    2585             :     else
    2586           0 :         result = time2;
    2587           0 :     PG_RETURN_TIMETZADT_P(result);
    2588             : }
    2589             : 
    2590             : Datum
    2591           0 : timetz_smaller(PG_FUNCTION_ARGS)
    2592             : {
    2593           0 :     TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
    2594           0 :     TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
    2595             :     TimeTzADT  *result;
    2596             : 
    2597           0 :     if (timetz_cmp_internal(time1, time2) < 0)
    2598           0 :         result = time1;
    2599             :     else
    2600           0 :         result = time2;
    2601           0 :     PG_RETURN_TIMETZADT_P(result);
    2602             : }
    2603             : 
    2604             : /* timetz_pl_interval()
    2605             :  * Add interval to timetz.
    2606             :  */
    2607             : Datum
    2608        2718 : timetz_pl_interval(PG_FUNCTION_ARGS)
    2609             : {
    2610        2718 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
    2611        2718 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2612             :     TimeTzADT  *result;
    2613             : 
    2614        2718 :     if (INTERVAL_NOT_FINITE(span))
    2615          12 :         ereport(ERROR,
    2616             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2617             :                  errmsg("cannot add infinite interval to time")));
    2618             : 
    2619        2706 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2620             : 
    2621        2706 :     result->time = time->time + span->time;
    2622        2706 :     result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
    2623        2706 :     if (result->time < INT64CONST(0))
    2624           0 :         result->time += USECS_PER_DAY;
    2625             : 
    2626        2706 :     result->zone = time->zone;
    2627             : 
    2628        2706 :     PG_RETURN_TIMETZADT_P(result);
    2629             : }
    2630             : 
    2631             : /* timetz_mi_interval()
    2632             :  * Subtract interval from timetz.
    2633             :  */
    2634             : Datum
    2635         738 : timetz_mi_interval(PG_FUNCTION_ARGS)
    2636             : {
    2637         738 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
    2638         738 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2639             :     TimeTzADT  *result;
    2640             : 
    2641         738 :     if (INTERVAL_NOT_FINITE(span))
    2642          12 :         ereport(ERROR,
    2643             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2644             :                  errmsg("cannot subtract infinite interval from time")));
    2645             : 
    2646         726 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2647             : 
    2648         726 :     result->time = time->time - span->time;
    2649         726 :     result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
    2650         726 :     if (result->time < INT64CONST(0))
    2651          78 :         result->time += USECS_PER_DAY;
    2652             : 
    2653         726 :     result->zone = time->zone;
    2654             : 
    2655         726 :     PG_RETURN_TIMETZADT_P(result);
    2656             : }
    2657             : 
    2658             : /*
    2659             :  * in_range support function for timetz.
    2660             :  */
    2661             : Datum
    2662        1038 : in_range_timetz_interval(PG_FUNCTION_ARGS)
    2663             : {
    2664        1038 :     TimeTzADT  *val = PG_GETARG_TIMETZADT_P(0);
    2665        1038 :     TimeTzADT  *base = PG_GETARG_TIMETZADT_P(1);
    2666        1038 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    2667        1038 :     bool        sub = PG_GETARG_BOOL(3);
    2668        1038 :     bool        less = PG_GETARG_BOOL(4);
    2669             :     TimeTzADT   sum;
    2670             : 
    2671             :     /*
    2672             :      * Like timetz_pl_interval/timetz_mi_interval, we disregard the month and
    2673             :      * day fields of the offset.  So our test for negative should too. This
    2674             :      * also catches -infinity, so we only need worry about +infinity below.
    2675             :      */
    2676        1038 :     if (offset->time < 0)
    2677          12 :         ereport(ERROR,
    2678             :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    2679             :                  errmsg("invalid preceding or following size in window function")));
    2680             : 
    2681             :     /*
    2682             :      * We can't use timetz_pl_interval/timetz_mi_interval here, because their
    2683             :      * wraparound behavior would give wrong (or at least undesirable) answers.
    2684             :      * Fortunately the equivalent non-wrapping behavior is trivial, except
    2685             :      * that adding an infinite (or very large) interval might cause integer
    2686             :      * overflow.  Subtraction cannot overflow here.
    2687             :      */
    2688        1026 :     if (sub)
    2689         474 :         sum.time = base->time - offset->time;
    2690         552 :     else if (pg_add_s64_overflow(base->time, offset->time, &sum.time))
    2691         288 :         PG_RETURN_BOOL(less);
    2692         738 :     sum.zone = base->zone;
    2693             : 
    2694         738 :     if (less)
    2695         336 :         PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) <= 0);
    2696             :     else
    2697         402 :         PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) >= 0);
    2698             : }
    2699             : 
    2700             : /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
    2701             :  *
    2702             :  * Algorithm is per SQL spec.  This is much harder than you'd think
    2703             :  * because the spec requires us to deliver a non-null answer in some cases
    2704             :  * where some of the inputs are null.
    2705             :  */
    2706             : Datum
    2707           0 : overlaps_timetz(PG_FUNCTION_ARGS)
    2708             : {
    2709             :     /*
    2710             :      * The arguments are TimeTzADT *, but we leave them as generic Datums for
    2711             :      * convenience of notation --- and to avoid dereferencing nulls.
    2712             :      */
    2713           0 :     Datum       ts1 = PG_GETARG_DATUM(0);
    2714           0 :     Datum       te1 = PG_GETARG_DATUM(1);
    2715           0 :     Datum       ts2 = PG_GETARG_DATUM(2);
    2716           0 :     Datum       te2 = PG_GETARG_DATUM(3);
    2717           0 :     bool        ts1IsNull = PG_ARGISNULL(0);
    2718           0 :     bool        te1IsNull = PG_ARGISNULL(1);
    2719           0 :     bool        ts2IsNull = PG_ARGISNULL(2);
    2720           0 :     bool        te2IsNull = PG_ARGISNULL(3);
    2721             : 
    2722             : #define TIMETZ_GT(t1,t2) \
    2723             :     DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
    2724             : #define TIMETZ_LT(t1,t2) \
    2725             :     DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
    2726             : 
    2727             :     /*
    2728             :      * If both endpoints of interval 1 are null, the result is null (unknown).
    2729             :      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
    2730             :      * take ts1 as the lesser endpoint.
    2731             :      */
    2732           0 :     if (ts1IsNull)
    2733             :     {
    2734           0 :         if (te1IsNull)
    2735           0 :             PG_RETURN_NULL();
    2736             :         /* swap null for non-null */
    2737           0 :         ts1 = te1;
    2738           0 :         te1IsNull = true;
    2739             :     }
    2740           0 :     else if (!te1IsNull)
    2741             :     {
    2742           0 :         if (TIMETZ_GT(ts1, te1))
    2743             :         {
    2744           0 :             Datum       tt = ts1;
    2745             : 
    2746           0 :             ts1 = te1;
    2747           0 :             te1 = tt;
    2748             :         }
    2749             :     }
    2750             : 
    2751             :     /* Likewise for interval 2. */
    2752           0 :     if (ts2IsNull)
    2753             :     {
    2754           0 :         if (te2IsNull)
    2755           0 :             PG_RETURN_NULL();
    2756             :         /* swap null for non-null */
    2757           0 :         ts2 = te2;
    2758           0 :         te2IsNull = true;
    2759             :     }
    2760           0 :     else if (!te2IsNull)
    2761             :     {
    2762           0 :         if (TIMETZ_GT(ts2, te2))
    2763             :         {
    2764           0 :             Datum       tt = ts2;
    2765             : 
    2766           0 :             ts2 = te2;
    2767           0 :             te2 = tt;
    2768             :         }
    2769             :     }
    2770             : 
    2771             :     /*
    2772             :      * At this point neither ts1 nor ts2 is null, so we can consider three
    2773             :      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
    2774             :      */
    2775           0 :     if (TIMETZ_GT(ts1, ts2))
    2776             :     {
    2777             :         /*
    2778             :          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
    2779             :          * in the presence of nulls it's not quite completely so.
    2780             :          */
    2781           0 :         if (te2IsNull)
    2782           0 :             PG_RETURN_NULL();
    2783           0 :         if (TIMETZ_LT(ts1, te2))
    2784           0 :             PG_RETURN_BOOL(true);
    2785           0 :         if (te1IsNull)
    2786           0 :             PG_RETURN_NULL();
    2787             : 
    2788             :         /*
    2789             :          * If te1 is not null then we had ts1 <= te1 above, and we just found
    2790             :          * ts1 >= te2, hence te1 >= te2.
    2791             :          */
    2792           0 :         PG_RETURN_BOOL(false);
    2793             :     }
    2794           0 :     else if (TIMETZ_LT(ts1, ts2))
    2795             :     {
    2796             :         /* This case is ts2 < te1 OR te2 < te1 */
    2797           0 :         if (te1IsNull)
    2798           0 :             PG_RETURN_NULL();
    2799           0 :         if (TIMETZ_LT(ts2, te1))
    2800           0 :             PG_RETURN_BOOL(true);
    2801           0 :         if (te2IsNull)
    2802           0 :             PG_RETURN_NULL();
    2803             : 
    2804             :         /*
    2805             :          * If te2 is not null then we had ts2 <= te2 above, and we just found
    2806             :          * ts2 >= te1, hence te2 >= te1.
    2807             :          */
    2808           0 :         PG_RETURN_BOOL(false);
    2809             :     }
    2810             :     else
    2811             :     {
    2812             :         /*
    2813             :          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
    2814             :          * rather silly way of saying "true if both are nonnull, else null".
    2815             :          */
    2816           0 :         if (te1IsNull || te2IsNull)
    2817           0 :             PG_RETURN_NULL();
    2818           0 :         PG_RETURN_BOOL(true);
    2819             :     }
    2820             : 
    2821             : #undef TIMETZ_GT
    2822             : #undef TIMETZ_LT
    2823             : }
    2824             : 
    2825             : 
    2826             : Datum
    2827          84 : timetz_time(PG_FUNCTION_ARGS)
    2828             : {
    2829          84 :     TimeTzADT  *timetz = PG_GETARG_TIMETZADT_P(0);
    2830             :     TimeADT     result;
    2831             : 
    2832             :     /* swallow the time zone and just return the time */
    2833          84 :     result = timetz->time;
    2834             : 
    2835          84 :     PG_RETURN_TIMEADT(result);
    2836             : }
    2837             : 
    2838             : 
    2839             : Datum
    2840         312 : time_timetz(PG_FUNCTION_ARGS)
    2841             : {
    2842         312 :     TimeADT     time = PG_GETARG_TIMEADT(0);
    2843             :     TimeTzADT  *result;
    2844             :     struct pg_tm tt,
    2845         312 :                *tm = &tt;
    2846             :     fsec_t      fsec;
    2847             :     int         tz;
    2848             : 
    2849         312 :     GetCurrentDateTime(tm);
    2850         312 :     time2tm(time, tm, &fsec);
    2851         312 :     tz = DetermineTimeZoneOffset(tm, session_timezone);
    2852             : 
    2853         312 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2854             : 
    2855         312 :     result->time = time;
    2856         312 :     result->zone = tz;
    2857             : 
    2858         312 :     PG_RETURN_TIMETZADT_P(result);
    2859             : }
    2860             : 
    2861             : 
    2862             : /* timestamptz_timetz()
    2863             :  * Convert timestamp to timetz data type.
    2864             :  */
    2865             : Datum
    2866          60 : timestamptz_timetz(PG_FUNCTION_ARGS)
    2867             : {
    2868          60 :     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
    2869             :     TimeTzADT  *result;
    2870             :     struct pg_tm tt,
    2871          60 :                *tm = &tt;
    2872             :     int         tz;
    2873             :     fsec_t      fsec;
    2874             : 
    2875          60 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    2876           0 :         PG_RETURN_NULL();
    2877             : 
    2878          60 :     if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    2879           0 :         ereport(ERROR,
    2880             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2881             :                  errmsg("timestamp out of range")));
    2882             : 
    2883          60 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    2884             : 
    2885          60 :     tm2timetz(tm, fsec, tz, result);
    2886             : 
    2887          60 :     PG_RETURN_TIMETZADT_P(result);
    2888             : }
    2889             : 
    2890             : 
    2891             : /* datetimetz_timestamptz()
    2892             :  * Convert date and timetz to timestamp with time zone data type.
    2893             :  * Timestamp is stored in GMT, so add the time zone
    2894             :  * stored with the timetz to the result.
    2895             :  * - thomas 2000-03-10
    2896             :  */
    2897             : Datum
    2898          54 : datetimetz_timestamptz(PG_FUNCTION_ARGS)
    2899             : {
    2900          54 :     DateADT     date = PG_GETARG_DATEADT(0);
    2901          54 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
    2902             :     TimestampTz result;
    2903             : 
    2904          54 :     if (DATE_IS_NOBEGIN(date))
    2905           0 :         TIMESTAMP_NOBEGIN(result);
    2906          54 :     else if (DATE_IS_NOEND(date))
    2907           0 :         TIMESTAMP_NOEND(result);
    2908             :     else
    2909             :     {
    2910             :         /*
    2911             :          * Date's range is wider than timestamp's, so check for boundaries.
    2912             :          * Since dates have the same minimum values as timestamps, only upper
    2913             :          * boundary need be checked for overflow.
    2914             :          */
    2915          54 :         if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
    2916           0 :             ereport(ERROR,
    2917             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2918             :                      errmsg("date out of range for timestamp")));
    2919          54 :         result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
    2920             : 
    2921             :         /*
    2922             :          * Since it is possible to go beyond allowed timestamptz range because
    2923             :          * of time zone, check for allowed timestamp range after adding tz.
    2924             :          */
    2925          54 :         if (!IS_VALID_TIMESTAMP(result))
    2926           0 :             ereport(ERROR,
    2927             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2928             :                      errmsg("date out of range for timestamp")));
    2929             :     }
    2930             : 
    2931          54 :     PG_RETURN_TIMESTAMP(result);
    2932             : }
    2933             : 
    2934             : 
    2935             : /* timetz_part() and extract_timetz()
    2936             :  * Extract specified field from time type.
    2937             :  */
    2938             : static Datum
    2939          90 : timetz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
    2940             : {
    2941          90 :     text       *units = PG_GETARG_TEXT_PP(0);
    2942          90 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
    2943             :     int64       intresult;
    2944             :     int         type,
    2945             :                 val;
    2946             :     char       *lowunits;
    2947             : 
    2948          90 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    2949          90 :                                             VARSIZE_ANY_EXHDR(units),
    2950             :                                             false);
    2951             : 
    2952          90 :     type = DecodeUnits(0, lowunits, &val);
    2953          90 :     if (type == UNKNOWN_FIELD)
    2954          18 :         type = DecodeSpecial(0, lowunits, &val);
    2955             : 
    2956          90 :     if (type == UNITS)
    2957             :     {
    2958             :         int         tz;
    2959             :         fsec_t      fsec;
    2960             :         struct pg_tm tt,
    2961          72 :                    *tm = &tt;
    2962             : 
    2963          72 :         timetz2tm(time, tm, &fsec, &tz);
    2964             : 
    2965          72 :         switch (val)
    2966             :         {
    2967           6 :             case DTK_TZ:
    2968           6 :                 intresult = -tz;
    2969           6 :                 break;
    2970             : 
    2971           6 :             case DTK_TZ_MINUTE:
    2972           6 :                 intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
    2973           6 :                 break;
    2974             : 
    2975           6 :             case DTK_TZ_HOUR:
    2976           6 :                 intresult = -tz / SECS_PER_HOUR;
    2977           6 :                 break;
    2978             : 
    2979          12 :             case DTK_MICROSEC:
    2980          12 :                 intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
    2981          12 :                 break;
    2982             : 
    2983          12 :             case DTK_MILLISEC:
    2984          12 :                 if (retnumeric)
    2985             :                     /*---
    2986             :                      * tm->tm_sec * 1000 + fsec / 1000
    2987             :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1000
    2988             :                      */
    2989          24 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
    2990             :                 else
    2991           6 :                     PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
    2992             :                 break;
    2993             : 
    2994          12 :             case DTK_SECOND:
    2995          12 :                 if (retnumeric)
    2996             :                     /*---
    2997             :                      * tm->tm_sec + fsec / 1'000'000
    2998             :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
    2999             :                      */
    3000           6 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
    3001             :                 else
    3002           6 :                     PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
    3003             :                 break;
    3004             : 
    3005           6 :             case DTK_MINUTE:
    3006           6 :                 intresult = tm->tm_min;
    3007           6 :                 break;
    3008             : 
    3009           6 :             case DTK_HOUR:
    3010           6 :                 intresult = tm->tm_hour;
    3011           6 :                 break;
    3012             : 
    3013           6 :             case DTK_DAY:
    3014             :             case DTK_MONTH:
    3015             :             case DTK_QUARTER:
    3016             :             case DTK_YEAR:
    3017             :             case DTK_DECADE:
    3018             :             case DTK_CENTURY:
    3019             :             case DTK_MILLENNIUM:
    3020             :             default:
    3021           6 :                 ereport(ERROR,
    3022             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3023             :                          errmsg("unit \"%s\" not supported for type %s",
    3024             :                                 lowunits, format_type_be(TIMETZOID))));
    3025             :                 intresult = 0;
    3026             :         }
    3027             :     }
    3028          18 :     else if (type == RESERV && val == DTK_EPOCH)
    3029             :     {
    3030          12 :         if (retnumeric)
    3031             :             /*---
    3032             :              * time->time / 1'000'000 + time->zone
    3033             :              * = (time->time + time->zone * 1'000'000) / 1'000'000
    3034             :              */
    3035           6 :             PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time->time + time->zone * INT64CONST(1000000), 6));
    3036             :         else
    3037           6 :             PG_RETURN_FLOAT8(time->time / 1000000.0 + time->zone);
    3038             :     }
    3039             :     else
    3040             :     {
    3041           6 :         ereport(ERROR,
    3042             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3043             :                  errmsg("unit \"%s\" not recognized for type %s",
    3044             :                         lowunits, format_type_be(TIMETZOID))));
    3045             :         intresult = 0;
    3046             :     }
    3047             : 
    3048          42 :     if (retnumeric)
    3049          36 :         PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    3050             :     else
    3051           6 :         PG_RETURN_FLOAT8(intresult);
    3052             : }
    3053             : 
    3054             : 
    3055             : Datum
    3056          24 : timetz_part(PG_FUNCTION_ARGS)
    3057             : {
    3058          24 :     return timetz_part_common(fcinfo, false);
    3059             : }
    3060             : 
    3061             : Datum
    3062          66 : extract_timetz(PG_FUNCTION_ARGS)
    3063             : {
    3064          66 :     return timetz_part_common(fcinfo, true);
    3065             : }
    3066             : 
    3067             : /* timetz_zone()
    3068             :  * Encode time with time zone type with specified time zone.
    3069             :  * Applies DST rules as of the transaction start time.
    3070             :  */
    3071             : Datum
    3072         288 : timetz_zone(PG_FUNCTION_ARGS)
    3073             : {
    3074         288 :     text       *zone = PG_GETARG_TEXT_PP(0);
    3075         288 :     TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
    3076             :     TimeTzADT  *result;
    3077             :     int         tz;
    3078             :     char        tzname[TZ_STRLEN_MAX + 1];
    3079             :     int         type,
    3080             :                 val;
    3081             :     pg_tz      *tzp;
    3082             : 
    3083             :     /*
    3084             :      * Look up the requested timezone.
    3085             :      */
    3086         288 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    3087             : 
    3088         288 :     type = DecodeTimezoneName(tzname, &val, &tzp);
    3089             : 
    3090         288 :     if (type == TZNAME_FIXED_OFFSET)
    3091             :     {
    3092             :         /* fixed-offset abbreviation */
    3093         216 :         tz = -val;
    3094             :     }
    3095          72 :     else if (type == TZNAME_DYNTZ)
    3096             :     {
    3097             :         /* dynamic-offset abbreviation, resolve using transaction start time */
    3098           0 :         TimestampTz now = GetCurrentTransactionStartTimestamp();
    3099             :         int         isdst;
    3100             : 
    3101           0 :         tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
    3102             :     }
    3103             :     else
    3104             :     {
    3105             :         /* Get the offset-from-GMT that is valid now for the zone name */
    3106          72 :         TimestampTz now = GetCurrentTransactionStartTimestamp();
    3107             :         struct pg_tm tm;
    3108             :         fsec_t      fsec;
    3109             : 
    3110          72 :         if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
    3111           0 :             ereport(ERROR,
    3112             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3113             :                      errmsg("timestamp out of range")));
    3114             :     }
    3115             : 
    3116         288 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    3117             : 
    3118         288 :     result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
    3119             :     /* C99 modulo has the wrong sign convention for negative input */
    3120         306 :     while (result->time < INT64CONST(0))
    3121          18 :         result->time += USECS_PER_DAY;
    3122         288 :     if (result->time >= USECS_PER_DAY)
    3123          36 :         result->time %= USECS_PER_DAY;
    3124             : 
    3125         288 :     result->zone = tz;
    3126             : 
    3127         288 :     PG_RETURN_TIMETZADT_P(result);
    3128             : }
    3129             : 
    3130             : /* timetz_izone()
    3131             :  * Encode time with time zone type with specified time interval as time zone.
    3132             :  */
    3133             : Datum
    3134         168 : timetz_izone(PG_FUNCTION_ARGS)
    3135             : {
    3136         168 :     Interval   *zone = PG_GETARG_INTERVAL_P(0);
    3137         168 :     TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
    3138             :     TimeTzADT  *result;
    3139             :     int         tz;
    3140             : 
    3141         168 :     if (INTERVAL_NOT_FINITE(zone))
    3142          24 :         ereport(ERROR,
    3143             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3144             :                  errmsg("interval time zone \"%s\" must be finite",
    3145             :                         DatumGetCString(DirectFunctionCall1(interval_out,
    3146             :                                                             PointerGetDatum(zone))))));
    3147             : 
    3148         144 :     if (zone->month != 0 || zone->day != 0)
    3149           0 :         ereport(ERROR,
    3150             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3151             :                  errmsg("interval time zone \"%s\" must not include months or days",
    3152             :                         DatumGetCString(DirectFunctionCall1(interval_out,
    3153             :                                                             PointerGetDatum(zone))))));
    3154             : 
    3155         144 :     tz = -(zone->time / USECS_PER_SEC);
    3156             : 
    3157         144 :     result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
    3158             : 
    3159         144 :     result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
    3160             :     /* C99 modulo has the wrong sign convention for negative input */
    3161         162 :     while (result->time < INT64CONST(0))
    3162          18 :         result->time += USECS_PER_DAY;
    3163         144 :     if (result->time >= USECS_PER_DAY)
    3164          12 :         result->time %= USECS_PER_DAY;
    3165             : 
    3166         144 :     result->zone = tz;
    3167             : 
    3168         144 :     PG_RETURN_TIMETZADT_P(result);
    3169             : }
    3170             : 
    3171             : /* timetz_at_local()
    3172             :  *
    3173             :  * Unlike for timestamp[tz]_at_local, the type for timetz does not flip between
    3174             :  * time with/without time zone, so we cannot just call the conversion function.
    3175             :  */
    3176             : Datum
    3177         144 : timetz_at_local(PG_FUNCTION_ARGS)
    3178             : {
    3179         144 :     Datum       time = PG_GETARG_DATUM(0);
    3180         144 :     const char *tzn = pg_get_timezone_name(session_timezone);
    3181         144 :     Datum       zone = PointerGetDatum(cstring_to_text(tzn));
    3182             : 
    3183         144 :     return DirectFunctionCall2(timetz_zone, zone, time);
    3184             : }

Generated by: LCOV version 1.14