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

Generated by: LCOV version 1.14