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

Generated by: LCOV version 1.14