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

Generated by: LCOV version 1.13