LCOV - code coverage report
Current view: top level - src/backend/utils/adt - date.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 549 1029 53.4 %
Date: 2019-06-18 07:06:57 Functions: 80 131 61.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13