LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 579 1063 54.5 %
Date: 2020-05-29 01:06:25 Functions: 84 133 63.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13