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

Generated by: LCOV version 1.16