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

Generated by: LCOV version 1.16