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

Generated by: LCOV version 2.0-1