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

Generated by: LCOV version 1.13