LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 887 1208 73.4 %
Date: 2025-04-24 12:15:10 Functions: 105 147 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14