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

Generated by: LCOV version 1.11