LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15beta1 Lines: 813 1162 70.0 %
Date: 2022-05-18 03:10:05 Functions: 100 141 70.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14