LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 887 1187 74.7 %
Date: 2025-01-18 04:15:08 Functions: 105 144 72.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14