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

Generated by: LCOV version 2.0-1