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

Generated by: LCOV version 2.0-1