LCOV - code coverage report
Current view: top level - src/backend/utils/adt - timestamp.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 77.0 % 2569 1977
Test Date: 2026-03-10 19:16:50 Functions: 85.5 % 193 165
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * timestamp.c
       4              :  *    Functions for the built-in SQL types "timestamp" and "interval".
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/utils/adt/timestamp.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres.h"
      17              : 
      18              : #include <ctype.h>
      19              : #include <math.h>
      20              : #include <limits.h>
      21              : #include <sys/time.h>
      22              : 
      23              : #include "access/xact.h"
      24              : #include "catalog/pg_type.h"
      25              : #include "common/int.h"
      26              : #include "common/int128.h"
      27              : #include "funcapi.h"
      28              : #include "libpq/pqformat.h"
      29              : #include "miscadmin.h"
      30              : #include "nodes/nodeFuncs.h"
      31              : #include "nodes/supportnodes.h"
      32              : #include "optimizer/optimizer.h"
      33              : #include "parser/scansup.h"
      34              : #include "utils/array.h"
      35              : #include "utils/builtins.h"
      36              : #include "utils/date.h"
      37              : #include "utils/datetime.h"
      38              : #include "utils/float.h"
      39              : #include "utils/numeric.h"
      40              : #include "utils/skipsupport.h"
      41              : #include "utils/sortsupport.h"
      42              : 
      43              : /*
      44              :  * gcc's -ffast-math switch breaks routines that expect exact results from
      45              :  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
      46              :  */
      47              : #ifdef __FAST_MATH__
      48              : #error -ffast-math is known to break this code
      49              : #endif
      50              : 
      51              : /* Set at postmaster start */
      52              : TimestampTz PgStartTime;
      53              : 
      54              : /* Set at configuration reload */
      55              : TimestampTz PgReloadTime;
      56              : 
      57              : typedef struct
      58              : {
      59              :     Timestamp   current;
      60              :     Timestamp   finish;
      61              :     Interval    step;
      62              :     int         step_sign;
      63              : } generate_series_timestamp_fctx;
      64              : 
      65              : typedef struct
      66              : {
      67              :     TimestampTz current;
      68              :     TimestampTz finish;
      69              :     Interval    step;
      70              :     int         step_sign;
      71              :     pg_tz      *attimezone;
      72              : } generate_series_timestamptz_fctx;
      73              : 
      74              : /*
      75              :  * The transition datatype for interval aggregates is declared as internal.
      76              :  * It's a pointer to an IntervalAggState allocated in the aggregate context.
      77              :  */
      78              : typedef struct IntervalAggState
      79              : {
      80              :     int64       N;              /* count of finite intervals processed */
      81              :     Interval    sumX;           /* sum of finite intervals processed */
      82              :     /* These counts are *not* included in N!  Use IA_TOTAL_COUNT() as needed */
      83              :     int64       pInfcount;      /* count of +infinity intervals */
      84              :     int64       nInfcount;      /* count of -infinity intervals */
      85              : } IntervalAggState;
      86              : 
      87              : #define IA_TOTAL_COUNT(ia) \
      88              :     ((ia)->N + (ia)->pInfcount + (ia)->nInfcount)
      89              : 
      90              : static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
      91              : static Timestamp dt2local(Timestamp dt, int timezone);
      92              : static bool AdjustIntervalForTypmod(Interval *interval, int32 typmod,
      93              :                                     Node *escontext);
      94              : static TimestampTz timestamp2timestamptz(Timestamp timestamp);
      95              : static Timestamp timestamptz2timestamp(TimestampTz timestamp);
      96              : 
      97              : static void EncodeSpecialInterval(const Interval *interval, char *str);
      98              : static void interval_um_internal(const Interval *interval, Interval *result);
      99              : 
     100              : /* common code for timestamptypmodin and timestamptztypmodin */
     101              : static int32
     102           78 : anytimestamp_typmodin(bool istz, ArrayType *ta)
     103              : {
     104              :     int32      *tl;
     105              :     int         n;
     106              : 
     107           78 :     tl = ArrayGetIntegerTypmods(ta, &n);
     108              : 
     109              :     /*
     110              :      * we're not too tense about good error message here because grammar
     111              :      * shouldn't allow wrong number of modifiers for TIMESTAMP
     112              :      */
     113           78 :     if (n != 1)
     114            0 :         ereport(ERROR,
     115              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     116              :                  errmsg("invalid type modifier")));
     117              : 
     118           78 :     return anytimestamp_typmod_check(istz, tl[0]);
     119              : }
     120              : 
     121              : /* exported so parse_expr.c can use it */
     122              : int32
     123          364 : anytimestamp_typmod_check(bool istz, int32 typmod)
     124              : {
     125          364 :     if (typmod < 0)
     126            0 :         ereport(ERROR,
     127              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     128              :                  errmsg("TIMESTAMP(%d)%s precision must not be negative",
     129              :                         typmod, (istz ? " WITH TIME ZONE" : ""))));
     130          364 :     if (typmod > MAX_TIMESTAMP_PRECISION)
     131              :     {
     132           18 :         ereport(WARNING,
     133              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     134              :                  errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
     135              :                         typmod, (istz ? " WITH TIME ZONE" : ""),
     136              :                         MAX_TIMESTAMP_PRECISION)));
     137           18 :         typmod = MAX_TIMESTAMP_PRECISION;
     138              :     }
     139              : 
     140          364 :     return typmod;
     141              : }
     142              : 
     143              : /* common code for timestamptypmodout and timestamptztypmodout */
     144              : static char *
     145           10 : anytimestamp_typmodout(bool istz, int32 typmod)
     146              : {
     147           10 :     const char *tz = istz ? " with time zone" : " without time zone";
     148              : 
     149           10 :     if (typmod >= 0)
     150           10 :         return psprintf("(%d)%s", (int) typmod, tz);
     151              :     else
     152            0 :         return pstrdup(tz);
     153              : }
     154              : 
     155              : 
     156              : /*****************************************************************************
     157              :  *   USER I/O ROUTINES                                                       *
     158              :  *****************************************************************************/
     159              : 
     160              : /* timestamp_in()
     161              :  * Convert a string to internal form.
     162              :  */
     163              : Datum
     164         8826 : timestamp_in(PG_FUNCTION_ARGS)
     165              : {
     166         8826 :     char       *str = PG_GETARG_CSTRING(0);
     167              : #ifdef NOT_USED
     168              :     Oid         typelem = PG_GETARG_OID(1);
     169              : #endif
     170         8826 :     int32       typmod = PG_GETARG_INT32(2);
     171         8826 :     Node       *escontext = fcinfo->context;
     172              :     Timestamp   result;
     173              :     fsec_t      fsec;
     174              :     struct pg_tm tt,
     175         8826 :                *tm = &tt;
     176              :     int         tz;
     177              :     int         dtype;
     178              :     int         nf;
     179              :     int         dterr;
     180              :     char       *field[MAXDATEFIELDS];
     181              :     int         ftype[MAXDATEFIELDS];
     182              :     char        workbuf[MAXDATELEN + MAXDATEFIELDS];
     183              :     DateTimeErrorExtra extra;
     184              : 
     185         8826 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     186              :                           field, ftype, MAXDATEFIELDS, &nf);
     187         8826 :     if (dterr == 0)
     188         8826 :         dterr = DecodeDateTime(field, ftype, nf,
     189              :                                &dtype, tm, &fsec, &tz, &extra);
     190         8826 :     if (dterr != 0)
     191              :     {
     192           57 :         DateTimeParseError(dterr, &extra, str, "timestamp", escontext);
     193           12 :         PG_RETURN_NULL();
     194              :     }
     195              : 
     196         8769 :     switch (dtype)
     197              :     {
     198         8574 :         case DTK_DATE:
     199         8574 :             if (tm2timestamp(tm, fsec, NULL, &result) != 0)
     200            9 :                 ereturn(escontext, (Datum) 0,
     201              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     202              :                          errmsg("timestamp out of range: \"%s\"", str)));
     203         8565 :             break;
     204              : 
     205           12 :         case DTK_EPOCH:
     206           12 :             result = SetEpochTimestamp();
     207           12 :             break;
     208              : 
     209          106 :         case DTK_LATE:
     210          106 :             TIMESTAMP_NOEND(result);
     211          106 :             break;
     212              : 
     213           77 :         case DTK_EARLY:
     214           77 :             TIMESTAMP_NOBEGIN(result);
     215           77 :             break;
     216              : 
     217            0 :         default:
     218            0 :             elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
     219              :                  dtype, str);
     220              :             TIMESTAMP_NOEND(result);
     221              :     }
     222              : 
     223         8760 :     AdjustTimestampForTypmod(&result, typmod, escontext);
     224              : 
     225         8760 :     PG_RETURN_TIMESTAMP(result);
     226              : }
     227              : 
     228              : /* timestamp_out()
     229              :  * Convert a timestamp to external form.
     230              :  */
     231              : Datum
     232        21729 : timestamp_out(PG_FUNCTION_ARGS)
     233              : {
     234        21729 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     235              :     char       *result;
     236              :     struct pg_tm tt,
     237        21729 :                *tm = &tt;
     238              :     fsec_t      fsec;
     239              :     char        buf[MAXDATELEN + 1];
     240              : 
     241        21729 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     242          265 :         EncodeSpecialTimestamp(timestamp, buf);
     243        21464 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
     244        21464 :         EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
     245              :     else
     246            0 :         ereport(ERROR,
     247              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     248              :                  errmsg("timestamp out of range")));
     249              : 
     250        21729 :     result = pstrdup(buf);
     251        21729 :     PG_RETURN_CSTRING(result);
     252              : }
     253              : 
     254              : /*
     255              :  *      timestamp_recv          - converts external binary format to timestamp
     256              :  */
     257              : Datum
     258            0 : timestamp_recv(PG_FUNCTION_ARGS)
     259              : {
     260            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     261              : 
     262              : #ifdef NOT_USED
     263              :     Oid         typelem = PG_GETARG_OID(1);
     264              : #endif
     265            0 :     int32       typmod = PG_GETARG_INT32(2);
     266              :     Timestamp   timestamp;
     267              :     struct pg_tm tt,
     268            0 :                *tm = &tt;
     269              :     fsec_t      fsec;
     270              : 
     271            0 :     timestamp = (Timestamp) pq_getmsgint64(buf);
     272              : 
     273              :     /* range check: see if timestamp_out would like it */
     274            0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     275              :          /* ok */ ;
     276            0 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
     277            0 :              !IS_VALID_TIMESTAMP(timestamp))
     278            0 :         ereport(ERROR,
     279              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     280              :                  errmsg("timestamp out of range")));
     281              : 
     282            0 :     AdjustTimestampForTypmod(&timestamp, typmod, NULL);
     283              : 
     284            0 :     PG_RETURN_TIMESTAMP(timestamp);
     285              : }
     286              : 
     287              : /*
     288              :  *      timestamp_send          - converts timestamp to binary format
     289              :  */
     290              : Datum
     291            0 : timestamp_send(PG_FUNCTION_ARGS)
     292              : {
     293            0 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     294              :     StringInfoData buf;
     295              : 
     296            0 :     pq_begintypsend(&buf);
     297            0 :     pq_sendint64(&buf, timestamp);
     298            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     299              : }
     300              : 
     301              : Datum
     302           18 : timestamptypmodin(PG_FUNCTION_ARGS)
     303              : {
     304           18 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     305              : 
     306           18 :     PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
     307              : }
     308              : 
     309              : Datum
     310            5 : timestamptypmodout(PG_FUNCTION_ARGS)
     311              : {
     312            5 :     int32       typmod = PG_GETARG_INT32(0);
     313              : 
     314            5 :     PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
     315              : }
     316              : 
     317              : 
     318              : /*
     319              :  * timestamp_support()
     320              :  *
     321              :  * Planner support function for the timestamp_scale() and timestamptz_scale()
     322              :  * length coercion functions (we need not distinguish them here).
     323              :  */
     324              : Datum
     325           12 : timestamp_support(PG_FUNCTION_ARGS)
     326              : {
     327           12 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
     328           12 :     Node       *ret = NULL;
     329              : 
     330           12 :     if (IsA(rawreq, SupportRequestSimplify))
     331              :     {
     332            6 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
     333              : 
     334            6 :         ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall);
     335              :     }
     336              : 
     337           12 :     PG_RETURN_POINTER(ret);
     338              : }
     339              : 
     340              : /* timestamp_scale()
     341              :  * Adjust time type for specified scale factor.
     342              :  * Used by PostgreSQL type system to stuff columns.
     343              :  */
     344              : Datum
     345        31086 : timestamp_scale(PG_FUNCTION_ARGS)
     346              : {
     347        31086 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     348        31086 :     int32       typmod = PG_GETARG_INT32(1);
     349              :     Timestamp   result;
     350              : 
     351        31086 :     result = timestamp;
     352              : 
     353        31086 :     AdjustTimestampForTypmod(&result, typmod, NULL);
     354              : 
     355        31086 :     PG_RETURN_TIMESTAMP(result);
     356              : }
     357              : 
     358              : /*
     359              :  * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
     360              :  * Works for either timestamp or timestamptz.
     361              :  *
     362              :  * Returns true on success, false on failure (if escontext points to an
     363              :  * ErrorSaveContext; otherwise errors are thrown).
     364              :  */
     365              : bool
     366        62929 : AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
     367              : {
     368              :     static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
     369              :         INT64CONST(1000000),
     370              :         INT64CONST(100000),
     371              :         INT64CONST(10000),
     372              :         INT64CONST(1000),
     373              :         INT64CONST(100),
     374              :         INT64CONST(10),
     375              :         INT64CONST(1)
     376              :     };
     377              : 
     378              :     static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
     379              :         INT64CONST(500000),
     380              :         INT64CONST(50000),
     381              :         INT64CONST(5000),
     382              :         INT64CONST(500),
     383              :         INT64CONST(50),
     384              :         INT64CONST(5),
     385              :         INT64CONST(0)
     386              :     };
     387              : 
     388        62929 :     if (!TIMESTAMP_NOT_FINITE(*time)
     389        62523 :         && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
     390              :     {
     391        31615 :         if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
     392            0 :             ereturn(escontext, false,
     393              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     394              :                      errmsg("timestamp(%d) precision must be between %d and %d",
     395              :                             typmod, 0, MAX_TIMESTAMP_PRECISION)));
     396              : 
     397        31615 :         if (*time >= INT64CONST(0))
     398              :         {
     399        31294 :             *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
     400        31294 :                 TimestampScales[typmod];
     401              :         }
     402              :         else
     403              :         {
     404          321 :             *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
     405          321 :                       * TimestampScales[typmod]);
     406              :         }
     407              :     }
     408              : 
     409        62929 :     return true;
     410              : }
     411              : 
     412              : /* timestamptz_in()
     413              :  * Convert a string to internal form.
     414              :  */
     415              : Datum
     416        20701 : timestamptz_in(PG_FUNCTION_ARGS)
     417              : {
     418        20701 :     char       *str = PG_GETARG_CSTRING(0);
     419              : #ifdef NOT_USED
     420              :     Oid         typelem = PG_GETARG_OID(1);
     421              : #endif
     422        20701 :     int32       typmod = PG_GETARG_INT32(2);
     423        20701 :     Node       *escontext = fcinfo->context;
     424              :     TimestampTz result;
     425              :     fsec_t      fsec;
     426              :     struct pg_tm tt,
     427        20701 :                *tm = &tt;
     428              :     int         tz;
     429              :     int         dtype;
     430              :     int         nf;
     431              :     int         dterr;
     432              :     char       *field[MAXDATEFIELDS];
     433              :     int         ftype[MAXDATEFIELDS];
     434              :     char        workbuf[MAXDATELEN + MAXDATEFIELDS];
     435              :     DateTimeErrorExtra extra;
     436              : 
     437        20701 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     438              :                           field, ftype, MAXDATEFIELDS, &nf);
     439        20701 :     if (dterr == 0)
     440        20701 :         dterr = DecodeDateTime(field, ftype, nf,
     441              :                                &dtype, tm, &fsec, &tz, &extra);
     442        20701 :     if (dterr != 0)
     443              :     {
     444           63 :         DateTimeParseError(dterr, &extra, str, "timestamp with time zone",
     445              :                            escontext);
     446           12 :         PG_RETURN_NULL();
     447              :     }
     448              : 
     449        20638 :     switch (dtype)
     450              :     {
     451        20421 :         case DTK_DATE:
     452        20421 :             if (tm2timestamp(tm, fsec, &tz, &result) != 0)
     453           12 :                 ereturn(escontext, (Datum) 0,
     454              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     455              :                          errmsg("timestamp out of range: \"%s\"", str)));
     456        20409 :             break;
     457              : 
     458            6 :         case DTK_EPOCH:
     459            6 :             result = SetEpochTimestamp();
     460            6 :             break;
     461              : 
     462          127 :         case DTK_LATE:
     463          127 :             TIMESTAMP_NOEND(result);
     464          127 :             break;
     465              : 
     466           84 :         case DTK_EARLY:
     467           84 :             TIMESTAMP_NOBEGIN(result);
     468           84 :             break;
     469              : 
     470            0 :         default:
     471            0 :             elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
     472              :                  dtype, str);
     473              :             TIMESTAMP_NOEND(result);
     474              :     }
     475              : 
     476        20626 :     AdjustTimestampForTypmod(&result, typmod, escontext);
     477              : 
     478        20626 :     PG_RETURN_TIMESTAMPTZ(result);
     479              : }
     480              : 
     481              : /*
     482              :  * Try to parse a timezone specification, and return its timezone offset value
     483              :  * if it's acceptable.  Otherwise, an error is thrown.
     484              :  *
     485              :  * Note: some code paths update tm->tm_isdst, and some don't; current callers
     486              :  * don't care, so we don't bother being consistent.
     487              :  */
     488              : static int
     489           99 : parse_sane_timezone(struct pg_tm *tm, text *zone)
     490              : {
     491              :     char        tzname[TZ_STRLEN_MAX + 1];
     492              :     int         dterr;
     493              :     int         tz;
     494              : 
     495           99 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
     496              : 
     497              :     /*
     498              :      * Look up the requested timezone.  First we try to interpret it as a
     499              :      * numeric timezone specification; if DecodeTimezone decides it doesn't
     500              :      * like the format, we try timezone abbreviations and names.
     501              :      *
     502              :      * Note pg_tzset happily parses numeric input that DecodeTimezone would
     503              :      * reject.  To avoid having it accept input that would otherwise be seen
     504              :      * as invalid, it's enough to disallow having a digit in the first
     505              :      * position of our input string.
     506              :      */
     507           99 :     if (isdigit((unsigned char) *tzname))
     508            3 :         ereport(ERROR,
     509              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     510              :                  errmsg("invalid input syntax for type %s: \"%s\"",
     511              :                         "numeric time zone", tzname),
     512              :                  errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
     513              : 
     514           96 :     dterr = DecodeTimezone(tzname, &tz);
     515           96 :     if (dterr != 0)
     516              :     {
     517              :         int         type,
     518              :                     val;
     519              :         pg_tz      *tzp;
     520              : 
     521           42 :         if (dterr == DTERR_TZDISP_OVERFLOW)
     522            6 :             ereport(ERROR,
     523              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     524              :                      errmsg("numeric time zone \"%s\" out of range", tzname)));
     525           36 :         else if (dterr != DTERR_BAD_FORMAT)
     526            0 :             ereport(ERROR,
     527              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     528              :                      errmsg("time zone \"%s\" not recognized", tzname)));
     529              : 
     530           36 :         type = DecodeTimezoneName(tzname, &val, &tzp);
     531              : 
     532           33 :         if (type == TZNAME_FIXED_OFFSET)
     533              :         {
     534              :             /* fixed-offset abbreviation */
     535            6 :             tz = -val;
     536              :         }
     537           27 :         else if (type == TZNAME_DYNTZ)
     538              :         {
     539              :             /* dynamic-offset abbreviation, resolve using specified time */
     540            6 :             tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
     541              :         }
     542              :         else
     543              :         {
     544              :             /* full zone name */
     545           21 :             tz = DetermineTimeZoneOffset(tm, tzp);
     546              :         }
     547              :     }
     548              : 
     549           87 :     return tz;
     550              : }
     551              : 
     552              : /*
     553              :  * Look up the requested timezone, returning a pg_tz struct.
     554              :  *
     555              :  * This is the same as DecodeTimezoneNameToTz, but starting with a text Datum.
     556              :  */
     557              : static pg_tz *
     558           48 : lookup_timezone(text *zone)
     559              : {
     560              :     char        tzname[TZ_STRLEN_MAX + 1];
     561              : 
     562           48 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
     563              : 
     564           48 :     return DecodeTimezoneNameToTz(tzname);
     565              : }
     566              : 
     567              : /*
     568              :  * make_timestamp_internal
     569              :  *      workhorse for make_timestamp and make_timestamptz
     570              :  */
     571              : static Timestamp
     572          117 : make_timestamp_internal(int year, int month, int day,
     573              :                         int hour, int min, double sec)
     574              : {
     575              :     struct pg_tm tm;
     576              :     TimeOffset  date;
     577              :     TimeOffset  time;
     578              :     int         dterr;
     579          117 :     bool        bc = false;
     580              :     Timestamp   result;
     581              : 
     582          117 :     tm.tm_year = year;
     583          117 :     tm.tm_mon = month;
     584          117 :     tm.tm_mday = day;
     585              : 
     586              :     /* Handle negative years as BC */
     587          117 :     if (tm.tm_year < 0)
     588              :     {
     589            3 :         bc = true;
     590            3 :         tm.tm_year = -tm.tm_year;
     591              :     }
     592              : 
     593          117 :     dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
     594              : 
     595          117 :     if (dterr != 0)
     596            3 :         ereport(ERROR,
     597              :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
     598              :                  errmsg("date field value out of range: %d-%02d-%02d",
     599              :                         year, month, day)));
     600              : 
     601          114 :     if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
     602            0 :         ereport(ERROR,
     603              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     604              :                  errmsg("date out of range: %d-%02d-%02d",
     605              :                         year, month, day)));
     606              : 
     607          114 :     date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
     608              : 
     609              :     /* Check for time overflow */
     610          114 :     if (float_time_overflows(hour, min, sec))
     611            0 :         ereport(ERROR,
     612              :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
     613              :                  errmsg("time field value out of range: %d:%02d:%02g",
     614              :                         hour, min, sec)));
     615              : 
     616              :     /* This should match tm2time */
     617          114 :     time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
     618          114 :             * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
     619              : 
     620          114 :     if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, &result) ||
     621              :                  pg_add_s64_overflow(result, time, &result)))
     622            0 :         ereport(ERROR,
     623              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     624              :                  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
     625              :                         year, month, day,
     626              :                         hour, min, sec)));
     627              : 
     628              :     /* final range check catches just-out-of-range timestamps */
     629          114 :     if (!IS_VALID_TIMESTAMP(result))
     630            0 :         ereport(ERROR,
     631              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     632              :                  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
     633              :                         year, month, day,
     634              :                         hour, min, sec)));
     635              : 
     636          114 :     return result;
     637              : }
     638              : 
     639              : /*
     640              :  * make_timestamp() - timestamp constructor
     641              :  */
     642              : Datum
     643           12 : make_timestamp(PG_FUNCTION_ARGS)
     644              : {
     645           12 :     int32       year = PG_GETARG_INT32(0);
     646           12 :     int32       month = PG_GETARG_INT32(1);
     647           12 :     int32       mday = PG_GETARG_INT32(2);
     648           12 :     int32       hour = PG_GETARG_INT32(3);
     649           12 :     int32       min = PG_GETARG_INT32(4);
     650           12 :     float8      sec = PG_GETARG_FLOAT8(5);
     651              :     Timestamp   result;
     652              : 
     653           12 :     result = make_timestamp_internal(year, month, mday,
     654              :                                      hour, min, sec);
     655              : 
     656            9 :     PG_RETURN_TIMESTAMP(result);
     657              : }
     658              : 
     659              : /*
     660              :  * make_timestamptz() - timestamp with time zone constructor
     661              :  */
     662              : Datum
     663            6 : make_timestamptz(PG_FUNCTION_ARGS)
     664              : {
     665            6 :     int32       year = PG_GETARG_INT32(0);
     666            6 :     int32       month = PG_GETARG_INT32(1);
     667            6 :     int32       mday = PG_GETARG_INT32(2);
     668            6 :     int32       hour = PG_GETARG_INT32(3);
     669            6 :     int32       min = PG_GETARG_INT32(4);
     670            6 :     float8      sec = PG_GETARG_FLOAT8(5);
     671              :     Timestamp   result;
     672              : 
     673            6 :     result = make_timestamp_internal(year, month, mday,
     674              :                                      hour, min, sec);
     675              : 
     676            6 :     PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
     677              : }
     678              : 
     679              : /*
     680              :  * Construct a timestamp with time zone.
     681              :  *      As above, but the time zone is specified as seventh argument.
     682              :  */
     683              : Datum
     684           99 : make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
     685              : {
     686           99 :     int32       year = PG_GETARG_INT32(0);
     687           99 :     int32       month = PG_GETARG_INT32(1);
     688           99 :     int32       mday = PG_GETARG_INT32(2);
     689           99 :     int32       hour = PG_GETARG_INT32(3);
     690           99 :     int32       min = PG_GETARG_INT32(4);
     691           99 :     float8      sec = PG_GETARG_FLOAT8(5);
     692           99 :     text       *zone = PG_GETARG_TEXT_PP(6);
     693              :     TimestampTz result;
     694              :     Timestamp   timestamp;
     695              :     struct pg_tm tt;
     696              :     int         tz;
     697              :     fsec_t      fsec;
     698              : 
     699           99 :     timestamp = make_timestamp_internal(year, month, mday,
     700              :                                         hour, min, sec);
     701              : 
     702           99 :     if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
     703            0 :         ereport(ERROR,
     704              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     705              :                  errmsg("timestamp out of range")));
     706              : 
     707           99 :     tz = parse_sane_timezone(&tt, zone);
     708              : 
     709           87 :     result = dt2local(timestamp, -tz);
     710              : 
     711           87 :     if (!IS_VALID_TIMESTAMP(result))
     712            0 :         ereport(ERROR,
     713              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     714              :                  errmsg("timestamp out of range")));
     715              : 
     716           87 :     PG_RETURN_TIMESTAMPTZ(result);
     717              : }
     718              : 
     719              : /*
     720              :  * to_timestamp(double precision)
     721              :  * Convert UNIX epoch to timestamptz.
     722              :  */
     723              : Datum
     724           27 : float8_timestamptz(PG_FUNCTION_ARGS)
     725              : {
     726           27 :     float8      seconds = PG_GETARG_FLOAT8(0);
     727              :     TimestampTz result;
     728              : 
     729              :     /* Deal with NaN and infinite inputs ... */
     730           27 :     if (isnan(seconds))
     731            3 :         ereport(ERROR,
     732              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     733              :                  errmsg("timestamp cannot be NaN")));
     734              : 
     735           24 :     if (isinf(seconds))
     736              :     {
     737            6 :         if (seconds < 0)
     738            3 :             TIMESTAMP_NOBEGIN(result);
     739              :         else
     740            3 :             TIMESTAMP_NOEND(result);
     741              :     }
     742              :     else
     743              :     {
     744              :         /* Out of range? */
     745           18 :         if (seconds <
     746              :             (float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
     747           18 :             || seconds >=
     748              :             (float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
     749            0 :             ereport(ERROR,
     750              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     751              :                      errmsg("timestamp out of range: \"%g\"", seconds)));
     752              : 
     753              :         /* Convert UNIX epoch to Postgres epoch */
     754           18 :         seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
     755              : 
     756           18 :         seconds = rint(seconds * USECS_PER_SEC);
     757           18 :         result = (int64) seconds;
     758              : 
     759              :         /* Recheck in case roundoff produces something just out of range */
     760           18 :         if (!IS_VALID_TIMESTAMP(result))
     761            0 :             ereport(ERROR,
     762              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     763              :                      errmsg("timestamp out of range: \"%g\"",
     764              :                             PG_GETARG_FLOAT8(0))));
     765              :     }
     766              : 
     767           24 :     PG_RETURN_TIMESTAMP(result);
     768              : }
     769              : 
     770              : /* timestamptz_out()
     771              :  * Convert a timestamp to external form.
     772              :  */
     773              : Datum
     774        35465 : timestamptz_out(PG_FUNCTION_ARGS)
     775              : {
     776        35465 :     TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
     777              :     char       *result;
     778              :     int         tz;
     779              :     struct pg_tm tt,
     780        35465 :                *tm = &tt;
     781              :     fsec_t      fsec;
     782              :     const char *tzn;
     783              :     char        buf[MAXDATELEN + 1];
     784              : 
     785        35465 :     if (TIMESTAMP_NOT_FINITE(dt))
     786          374 :         EncodeSpecialTimestamp(dt, buf);
     787        35091 :     else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
     788        35091 :         EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
     789              :     else
     790            0 :         ereport(ERROR,
     791              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     792              :                  errmsg("timestamp out of range")));
     793              : 
     794        35465 :     result = pstrdup(buf);
     795        35465 :     PG_RETURN_CSTRING(result);
     796              : }
     797              : 
     798              : /*
     799              :  *      timestamptz_recv            - converts external binary format to timestamptz
     800              :  */
     801              : Datum
     802            0 : timestamptz_recv(PG_FUNCTION_ARGS)
     803              : {
     804            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     805              : 
     806              : #ifdef NOT_USED
     807              :     Oid         typelem = PG_GETARG_OID(1);
     808              : #endif
     809            0 :     int32       typmod = PG_GETARG_INT32(2);
     810              :     TimestampTz timestamp;
     811              :     int         tz;
     812              :     struct pg_tm tt,
     813            0 :                *tm = &tt;
     814              :     fsec_t      fsec;
     815              : 
     816            0 :     timestamp = (TimestampTz) pq_getmsgint64(buf);
     817              : 
     818              :     /* range check: see if timestamptz_out would like it */
     819            0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     820              :          /* ok */ ;
     821            0 :     else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
     822            0 :              !IS_VALID_TIMESTAMP(timestamp))
     823            0 :         ereport(ERROR,
     824              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     825              :                  errmsg("timestamp out of range")));
     826              : 
     827            0 :     AdjustTimestampForTypmod(&timestamp, typmod, NULL);
     828              : 
     829            0 :     PG_RETURN_TIMESTAMPTZ(timestamp);
     830              : }
     831              : 
     832              : /*
     833              :  *      timestamptz_send            - converts timestamptz to binary format
     834              :  */
     835              : Datum
     836            0 : timestamptz_send(PG_FUNCTION_ARGS)
     837              : {
     838            0 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
     839              :     StringInfoData buf;
     840              : 
     841            0 :     pq_begintypsend(&buf);
     842            0 :     pq_sendint64(&buf, timestamp);
     843            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     844              : }
     845              : 
     846              : Datum
     847           60 : timestamptztypmodin(PG_FUNCTION_ARGS)
     848              : {
     849           60 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     850              : 
     851           60 :     PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
     852              : }
     853              : 
     854              : Datum
     855            5 : timestamptztypmodout(PG_FUNCTION_ARGS)
     856              : {
     857            5 :     int32       typmod = PG_GETARG_INT32(0);
     858              : 
     859            5 :     PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
     860              : }
     861              : 
     862              : 
     863              : /* timestamptz_scale()
     864              :  * Adjust time type for specified scale factor.
     865              :  * Used by PostgreSQL type system to stuff columns.
     866              :  */
     867              : Datum
     868          228 : timestamptz_scale(PG_FUNCTION_ARGS)
     869              : {
     870          228 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
     871          228 :     int32       typmod = PG_GETARG_INT32(1);
     872              :     TimestampTz result;
     873              : 
     874          228 :     result = timestamp;
     875              : 
     876          228 :     AdjustTimestampForTypmod(&result, typmod, NULL);
     877              : 
     878          228 :     PG_RETURN_TIMESTAMPTZ(result);
     879              : }
     880              : 
     881              : 
     882              : /* interval_in()
     883              :  * Convert a string to internal form.
     884              :  *
     885              :  * External format(s):
     886              :  *  Uses the generic date/time parsing and decoding routines.
     887              :  */
     888              : Datum
     889        32672 : interval_in(PG_FUNCTION_ARGS)
     890              : {
     891        32672 :     char       *str = PG_GETARG_CSTRING(0);
     892              : #ifdef NOT_USED
     893              :     Oid         typelem = PG_GETARG_OID(1);
     894              : #endif
     895        32672 :     int32       typmod = PG_GETARG_INT32(2);
     896        32672 :     Node       *escontext = fcinfo->context;
     897              :     Interval   *result;
     898              :     struct pg_itm_in tt,
     899        32672 :                *itm_in = &tt;
     900              :     int         dtype;
     901              :     int         nf;
     902              :     int         range;
     903              :     int         dterr;
     904              :     char       *field[MAXDATEFIELDS];
     905              :     int         ftype[MAXDATEFIELDS];
     906              :     char        workbuf[256];
     907              :     DateTimeErrorExtra extra;
     908              : 
     909        32672 :     itm_in->tm_year = 0;
     910        32672 :     itm_in->tm_mon = 0;
     911        32672 :     itm_in->tm_mday = 0;
     912        32672 :     itm_in->tm_usec = 0;
     913              : 
     914        32672 :     if (typmod >= 0)
     915          168 :         range = INTERVAL_RANGE(typmod);
     916              :     else
     917        32504 :         range = INTERVAL_FULL_RANGE;
     918              : 
     919        32672 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
     920              :                           ftype, MAXDATEFIELDS, &nf);
     921        32672 :     if (dterr == 0)
     922        32672 :         dterr = DecodeInterval(field, ftype, nf, range,
     923              :                                &dtype, itm_in);
     924              : 
     925              :     /* if those functions think it's a bad format, try ISO8601 style */
     926        32672 :     if (dterr == DTERR_BAD_FORMAT)
     927          306 :         dterr = DecodeISO8601Interval(str,
     928              :                                       &dtype, itm_in);
     929              : 
     930        32672 :     if (dterr != 0)
     931              :     {
     932          477 :         if (dterr == DTERR_FIELD_OVERFLOW)
     933          360 :             dterr = DTERR_INTERVAL_OVERFLOW;
     934          477 :         DateTimeParseError(dterr, &extra, str, "interval", escontext);
     935           12 :         PG_RETURN_NULL();
     936              :     }
     937              : 
     938        32195 :     result = palloc_object(Interval);
     939              : 
     940        32195 :     switch (dtype)
     941              :     {
     942        31709 :         case DTK_DELTA:
     943        31709 :             if (itmin2interval(itm_in, result) != 0)
     944            9 :                 ereturn(escontext, (Datum) 0,
     945              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     946              :                          errmsg("interval out of range")));
     947        31700 :             break;
     948              : 
     949          285 :         case DTK_LATE:
     950          285 :             INTERVAL_NOEND(result);
     951          285 :             break;
     952              : 
     953          201 :         case DTK_EARLY:
     954          201 :             INTERVAL_NOBEGIN(result);
     955          201 :             break;
     956              : 
     957            0 :         default:
     958            0 :             elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
     959              :                  dtype, str);
     960              :     }
     961              : 
     962        32186 :     AdjustIntervalForTypmod(result, typmod, escontext);
     963              : 
     964        32180 :     PG_RETURN_INTERVAL_P(result);
     965              : }
     966              : 
     967              : /* interval_out()
     968              :  * Convert a time span to external form.
     969              :  */
     970              : Datum
     971         8157 : interval_out(PG_FUNCTION_ARGS)
     972              : {
     973         8157 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
     974              :     char       *result;
     975              :     struct pg_itm tt,
     976         8157 :                *itm = &tt;
     977              :     char        buf[MAXDATELEN + 1];
     978              : 
     979         8157 :     if (INTERVAL_NOT_FINITE(span))
     980         1012 :         EncodeSpecialInterval(span, buf);
     981              :     else
     982              :     {
     983         7145 :         interval2itm(*span, itm);
     984         7145 :         EncodeInterval(itm, IntervalStyle, buf);
     985              :     }
     986              : 
     987         8157 :     result = pstrdup(buf);
     988         8157 :     PG_RETURN_CSTRING(result);
     989              : }
     990              : 
     991              : /*
     992              :  *      interval_recv           - converts external binary format to interval
     993              :  */
     994              : Datum
     995            0 : interval_recv(PG_FUNCTION_ARGS)
     996              : {
     997            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     998              : 
     999              : #ifdef NOT_USED
    1000              :     Oid         typelem = PG_GETARG_OID(1);
    1001              : #endif
    1002            0 :     int32       typmod = PG_GETARG_INT32(2);
    1003              :     Interval   *interval;
    1004              : 
    1005            0 :     interval = palloc_object(Interval);
    1006              : 
    1007            0 :     interval->time = pq_getmsgint64(buf);
    1008            0 :     interval->day = pq_getmsgint(buf, sizeof(interval->day));
    1009            0 :     interval->month = pq_getmsgint(buf, sizeof(interval->month));
    1010              : 
    1011            0 :     AdjustIntervalForTypmod(interval, typmod, NULL);
    1012              : 
    1013            0 :     PG_RETURN_INTERVAL_P(interval);
    1014              : }
    1015              : 
    1016              : /*
    1017              :  *      interval_send           - converts interval to binary format
    1018              :  */
    1019              : Datum
    1020            0 : interval_send(PG_FUNCTION_ARGS)
    1021              : {
    1022            0 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    1023              :     StringInfoData buf;
    1024              : 
    1025            0 :     pq_begintypsend(&buf);
    1026            0 :     pq_sendint64(&buf, interval->time);
    1027            0 :     pq_sendint32(&buf, interval->day);
    1028            0 :     pq_sendint32(&buf, interval->month);
    1029            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1030              : }
    1031              : 
    1032              : /*
    1033              :  * The interval typmod stores a "range" in its high 16 bits and a "precision"
    1034              :  * in its low 16 bits.  Both contribute to defining the resolution of the
    1035              :  * type.  Range addresses resolution granules larger than one second, and
    1036              :  * precision specifies resolution below one second.  This representation can
    1037              :  * express all SQL standard resolutions, but we implement them all in terms of
    1038              :  * truncating rightward from some position.  Range is a bitmap of permitted
    1039              :  * fields, but only the temporally-smallest such field is significant to our
    1040              :  * calculations.  Precision is a count of sub-second decimal places to retain.
    1041              :  * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation
    1042              :  * semantics as choosing MAX_INTERVAL_PRECISION.
    1043              :  */
    1044              : Datum
    1045          177 : intervaltypmodin(PG_FUNCTION_ARGS)
    1046              : {
    1047          177 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
    1048              :     int32      *tl;
    1049              :     int         n;
    1050              :     int32       typmod;
    1051              : 
    1052          177 :     tl = ArrayGetIntegerTypmods(ta, &n);
    1053              : 
    1054              :     /*
    1055              :      * tl[0] - interval range (fields bitmask)  tl[1] - precision (optional)
    1056              :      *
    1057              :      * Note we must validate tl[0] even though it's normally guaranteed
    1058              :      * correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
    1059              :      */
    1060          177 :     if (n > 0)
    1061              :     {
    1062          177 :         switch (tl[0])
    1063              :         {
    1064          177 :             case INTERVAL_MASK(YEAR):
    1065              :             case INTERVAL_MASK(MONTH):
    1066              :             case INTERVAL_MASK(DAY):
    1067              :             case INTERVAL_MASK(HOUR):
    1068              :             case INTERVAL_MASK(MINUTE):
    1069              :             case INTERVAL_MASK(SECOND):
    1070              :             case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1071              :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1072              :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1073              :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1074              :             case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1075              :             case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1076              :             case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1077              :             case INTERVAL_FULL_RANGE:
    1078              :                 /* all OK */
    1079          177 :                 break;
    1080            0 :             default:
    1081            0 :                 ereport(ERROR,
    1082              :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1083              :                          errmsg("invalid INTERVAL type modifier")));
    1084              :         }
    1085              :     }
    1086              : 
    1087          177 :     if (n == 1)
    1088              :     {
    1089          129 :         if (tl[0] != INTERVAL_FULL_RANGE)
    1090          129 :             typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
    1091              :         else
    1092            0 :             typmod = -1;
    1093              :     }
    1094           48 :     else if (n == 2)
    1095              :     {
    1096           48 :         if (tl[1] < 0)
    1097            0 :             ereport(ERROR,
    1098              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1099              :                      errmsg("INTERVAL(%d) precision must not be negative",
    1100              :                             tl[1])));
    1101           48 :         if (tl[1] > MAX_INTERVAL_PRECISION)
    1102              :         {
    1103            0 :             ereport(WARNING,
    1104              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1105              :                      errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
    1106              :                             tl[1], MAX_INTERVAL_PRECISION)));
    1107            0 :             typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
    1108              :         }
    1109              :         else
    1110           48 :             typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
    1111              :     }
    1112              :     else
    1113              :     {
    1114            0 :         ereport(ERROR,
    1115              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1116              :                  errmsg("invalid INTERVAL type modifier")));
    1117              :         typmod = 0;             /* keep compiler quiet */
    1118              :     }
    1119              : 
    1120          177 :     PG_RETURN_INT32(typmod);
    1121              : }
    1122              : 
    1123              : Datum
    1124            0 : intervaltypmodout(PG_FUNCTION_ARGS)
    1125              : {
    1126            0 :     int32       typmod = PG_GETARG_INT32(0);
    1127            0 :     char       *res = (char *) palloc(64);
    1128              :     int         fields;
    1129              :     int         precision;
    1130              :     const char *fieldstr;
    1131              : 
    1132            0 :     if (typmod < 0)
    1133              :     {
    1134            0 :         *res = '\0';
    1135            0 :         PG_RETURN_CSTRING(res);
    1136              :     }
    1137              : 
    1138            0 :     fields = INTERVAL_RANGE(typmod);
    1139            0 :     precision = INTERVAL_PRECISION(typmod);
    1140              : 
    1141            0 :     switch (fields)
    1142              :     {
    1143            0 :         case INTERVAL_MASK(YEAR):
    1144            0 :             fieldstr = " year";
    1145            0 :             break;
    1146            0 :         case INTERVAL_MASK(MONTH):
    1147            0 :             fieldstr = " month";
    1148            0 :             break;
    1149            0 :         case INTERVAL_MASK(DAY):
    1150            0 :             fieldstr = " day";
    1151            0 :             break;
    1152            0 :         case INTERVAL_MASK(HOUR):
    1153            0 :             fieldstr = " hour";
    1154            0 :             break;
    1155            0 :         case INTERVAL_MASK(MINUTE):
    1156            0 :             fieldstr = " minute";
    1157            0 :             break;
    1158            0 :         case INTERVAL_MASK(SECOND):
    1159            0 :             fieldstr = " second";
    1160            0 :             break;
    1161            0 :         case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1162            0 :             fieldstr = " year to month";
    1163            0 :             break;
    1164            0 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1165            0 :             fieldstr = " day to hour";
    1166            0 :             break;
    1167            0 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1168            0 :             fieldstr = " day to minute";
    1169            0 :             break;
    1170            0 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1171            0 :             fieldstr = " day to second";
    1172            0 :             break;
    1173            0 :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1174            0 :             fieldstr = " hour to minute";
    1175            0 :             break;
    1176            0 :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1177            0 :             fieldstr = " hour to second";
    1178            0 :             break;
    1179            0 :         case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1180            0 :             fieldstr = " minute to second";
    1181            0 :             break;
    1182            0 :         case INTERVAL_FULL_RANGE:
    1183            0 :             fieldstr = "";
    1184            0 :             break;
    1185            0 :         default:
    1186            0 :             elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
    1187              :             fieldstr = "";
    1188              :             break;
    1189              :     }
    1190              : 
    1191            0 :     if (precision != INTERVAL_FULL_PRECISION)
    1192            0 :         snprintf(res, 64, "%s(%d)", fieldstr, precision);
    1193              :     else
    1194            0 :         snprintf(res, 64, "%s", fieldstr);
    1195              : 
    1196            0 :     PG_RETURN_CSTRING(res);
    1197              : }
    1198              : 
    1199              : /*
    1200              :  * Given an interval typmod value, return a code for the least-significant
    1201              :  * field that the typmod allows to be nonzero, for instance given
    1202              :  * INTERVAL DAY TO HOUR we want to identify "hour".
    1203              :  *
    1204              :  * The results should be ordered by field significance, which means
    1205              :  * we can't use the dt.h macros YEAR etc, because for some odd reason
    1206              :  * they aren't ordered that way.  Instead, arbitrarily represent
    1207              :  * SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5.
    1208              :  */
    1209              : static int
    1210           18 : intervaltypmodleastfield(int32 typmod)
    1211              : {
    1212           18 :     if (typmod < 0)
    1213            6 :         return 0;               /* SECOND */
    1214              : 
    1215           12 :     switch (INTERVAL_RANGE(typmod))
    1216              :     {
    1217            3 :         case INTERVAL_MASK(YEAR):
    1218            3 :             return 5;           /* YEAR */
    1219            6 :         case INTERVAL_MASK(MONTH):
    1220            6 :             return 4;           /* MONTH */
    1221            0 :         case INTERVAL_MASK(DAY):
    1222            0 :             return 3;           /* DAY */
    1223            0 :         case INTERVAL_MASK(HOUR):
    1224            0 :             return 2;           /* HOUR */
    1225            0 :         case INTERVAL_MASK(MINUTE):
    1226            0 :             return 1;           /* MINUTE */
    1227            0 :         case INTERVAL_MASK(SECOND):
    1228            0 :             return 0;           /* SECOND */
    1229            0 :         case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1230            0 :             return 4;           /* MONTH */
    1231            0 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1232            0 :             return 2;           /* HOUR */
    1233            3 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1234            3 :             return 1;           /* MINUTE */
    1235            0 :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1236            0 :             return 0;           /* SECOND */
    1237            0 :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1238            0 :             return 1;           /* MINUTE */
    1239            0 :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1240            0 :             return 0;           /* SECOND */
    1241            0 :         case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1242            0 :             return 0;           /* SECOND */
    1243            0 :         case INTERVAL_FULL_RANGE:
    1244            0 :             return 0;           /* SECOND */
    1245            0 :         default:
    1246            0 :             elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
    1247              :             break;
    1248              :     }
    1249              :     return 0;                   /* can't get here, but keep compiler quiet */
    1250              : }
    1251              : 
    1252              : 
    1253              : /*
    1254              :  * interval_support()
    1255              :  *
    1256              :  * Planner support function for interval_scale().
    1257              :  *
    1258              :  * Flatten superfluous calls to interval_scale().  The interval typmod is
    1259              :  * complex to permit accepting and regurgitating all SQL standard variations.
    1260              :  * For truncation purposes, it boils down to a single, simple granularity.
    1261              :  */
    1262              : Datum
    1263           18 : interval_support(PG_FUNCTION_ARGS)
    1264              : {
    1265           18 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
    1266           18 :     Node       *ret = NULL;
    1267              : 
    1268           18 :     if (IsA(rawreq, SupportRequestSimplify))
    1269              :     {
    1270            9 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
    1271            9 :         FuncExpr   *expr = req->fcall;
    1272              :         Node       *typmod;
    1273              : 
    1274              :         Assert(list_length(expr->args) >= 2);
    1275              : 
    1276            9 :         typmod = (Node *) lsecond(expr->args);
    1277              : 
    1278            9 :         if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
    1279              :         {
    1280            9 :             Node       *source = (Node *) linitial(expr->args);
    1281            9 :             int32       new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
    1282              :             bool        noop;
    1283              : 
    1284            9 :             if (new_typmod < 0)
    1285            0 :                 noop = true;
    1286              :             else
    1287              :             {
    1288            9 :                 int32       old_typmod = exprTypmod(source);
    1289              :                 int         old_least_field;
    1290              :                 int         new_least_field;
    1291              :                 int         old_precis;
    1292              :                 int         new_precis;
    1293              : 
    1294            9 :                 old_least_field = intervaltypmodleastfield(old_typmod);
    1295            9 :                 new_least_field = intervaltypmodleastfield(new_typmod);
    1296            9 :                 if (old_typmod < 0)
    1297            6 :                     old_precis = INTERVAL_FULL_PRECISION;
    1298              :                 else
    1299            3 :                     old_precis = INTERVAL_PRECISION(old_typmod);
    1300            9 :                 new_precis = INTERVAL_PRECISION(new_typmod);
    1301              : 
    1302              :                 /*
    1303              :                  * Cast is a no-op if least field stays the same or decreases
    1304              :                  * while precision stays the same or increases.  But
    1305              :                  * precision, which is to say, sub-second precision, only
    1306              :                  * affects ranges that include SECOND.
    1307              :                  */
    1308            9 :                 noop = (new_least_field <= old_least_field) &&
    1309            0 :                     (old_least_field > 0 /* SECOND */ ||
    1310            0 :                      new_precis >= MAX_INTERVAL_PRECISION ||
    1311              :                      new_precis >= old_precis);
    1312              :             }
    1313            9 :             if (noop)
    1314            0 :                 ret = relabel_to_typmod(source, new_typmod);
    1315              :         }
    1316              :     }
    1317              : 
    1318           18 :     PG_RETURN_POINTER(ret);
    1319              : }
    1320              : 
    1321              : /* interval_scale()
    1322              :  * Adjust interval type for specified fields.
    1323              :  * Used by PostgreSQL type system to stuff columns.
    1324              :  */
    1325              : Datum
    1326          108 : interval_scale(PG_FUNCTION_ARGS)
    1327              : {
    1328          108 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    1329          108 :     int32       typmod = PG_GETARG_INT32(1);
    1330              :     Interval   *result;
    1331              : 
    1332          108 :     result = palloc_object(Interval);
    1333          108 :     *result = *interval;
    1334              : 
    1335          108 :     AdjustIntervalForTypmod(result, typmod, NULL);
    1336              : 
    1337          108 :     PG_RETURN_INTERVAL_P(result);
    1338              : }
    1339              : 
    1340              : /*
    1341              :  *  Adjust interval for specified precision, in both YEAR to SECOND
    1342              :  *  range and sub-second precision.
    1343              :  *
    1344              :  * Returns true on success, false on failure (if escontext points to an
    1345              :  * ErrorSaveContext; otherwise errors are thrown).
    1346              :  */
    1347              : static bool
    1348        32294 : AdjustIntervalForTypmod(Interval *interval, int32 typmod,
    1349              :                         Node *escontext)
    1350              : {
    1351              :     static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
    1352              :         INT64CONST(1000000),
    1353              :         INT64CONST(100000),
    1354              :         INT64CONST(10000),
    1355              :         INT64CONST(1000),
    1356              :         INT64CONST(100),
    1357              :         INT64CONST(10),
    1358              :         INT64CONST(1)
    1359              :     };
    1360              : 
    1361              :     static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
    1362              :         INT64CONST(500000),
    1363              :         INT64CONST(50000),
    1364              :         INT64CONST(5000),
    1365              :         INT64CONST(500),
    1366              :         INT64CONST(50),
    1367              :         INT64CONST(5),
    1368              :         INT64CONST(0)
    1369              :     };
    1370              : 
    1371              :     /* Typmod has no effect on infinite intervals */
    1372        32294 :     if (INTERVAL_NOT_FINITE(interval))
    1373          510 :         return true;
    1374              : 
    1375              :     /*
    1376              :      * Unspecified range and precision? Then not necessary to adjust. Setting
    1377              :      * typmod to -1 is the convention for all data types.
    1378              :      */
    1379        31784 :     if (typmod >= 0)
    1380              :     {
    1381          231 :         int         range = INTERVAL_RANGE(typmod);
    1382          231 :         int         precision = INTERVAL_PRECISION(typmod);
    1383              : 
    1384              :         /*
    1385              :          * Our interpretation of intervals with a limited set of fields is
    1386              :          * that fields to the right of the last one specified are zeroed out,
    1387              :          * but those to the left of it remain valid.  Thus for example there
    1388              :          * is no operational difference between INTERVAL YEAR TO MONTH and
    1389              :          * INTERVAL MONTH.  In some cases we could meaningfully enforce that
    1390              :          * higher-order fields are zero; for example INTERVAL DAY could reject
    1391              :          * nonzero "month" field.  However that seems a bit pointless when we
    1392              :          * can't do it consistently.  (We cannot enforce a range limit on the
    1393              :          * highest expected field, since we do not have any equivalent of
    1394              :          * SQL's <interval leading field precision>.)  If we ever decide to
    1395              :          * revisit this, interval_support will likely require adjusting.
    1396              :          *
    1397              :          * Note: before PG 8.4 we interpreted a limited set of fields as
    1398              :          * actually causing a "modulo" operation on a given value, potentially
    1399              :          * losing high-order as well as low-order information.  But there is
    1400              :          * no support for such behavior in the standard, and it seems fairly
    1401              :          * undesirable on data consistency grounds anyway.  Now we only
    1402              :          * perform truncation or rounding of low-order fields.
    1403              :          */
    1404          231 :         if (range == INTERVAL_FULL_RANGE)
    1405              :         {
    1406              :             /* Do nothing... */
    1407              :         }
    1408          225 :         else if (range == INTERVAL_MASK(YEAR))
    1409              :         {
    1410           33 :             interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
    1411           33 :             interval->day = 0;
    1412           33 :             interval->time = 0;
    1413              :         }
    1414          192 :         else if (range == INTERVAL_MASK(MONTH))
    1415              :         {
    1416           36 :             interval->day = 0;
    1417           36 :             interval->time = 0;
    1418              :         }
    1419              :         /* YEAR TO MONTH */
    1420          156 :         else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
    1421              :         {
    1422            9 :             interval->day = 0;
    1423            9 :             interval->time = 0;
    1424              :         }
    1425          147 :         else if (range == INTERVAL_MASK(DAY))
    1426              :         {
    1427            6 :             interval->time = 0;
    1428              :         }
    1429          141 :         else if (range == INTERVAL_MASK(HOUR))
    1430              :         {
    1431            6 :             interval->time = (interval->time / USECS_PER_HOUR) *
    1432              :                 USECS_PER_HOUR;
    1433              :         }
    1434          135 :         else if (range == INTERVAL_MASK(MINUTE))
    1435              :         {
    1436            6 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1437              :                 USECS_PER_MINUTE;
    1438              :         }
    1439          129 :         else if (range == INTERVAL_MASK(SECOND))
    1440              :         {
    1441              :             /* fractional-second rounding will be dealt with below */
    1442              :         }
    1443              :         /* DAY TO HOUR */
    1444          111 :         else if (range == (INTERVAL_MASK(DAY) |
    1445              :                            INTERVAL_MASK(HOUR)))
    1446              :         {
    1447           12 :             interval->time = (interval->time / USECS_PER_HOUR) *
    1448              :                 USECS_PER_HOUR;
    1449              :         }
    1450              :         /* DAY TO MINUTE */
    1451           99 :         else if (range == (INTERVAL_MASK(DAY) |
    1452              :                            INTERVAL_MASK(HOUR) |
    1453              :                            INTERVAL_MASK(MINUTE)))
    1454              :         {
    1455           36 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1456              :                 USECS_PER_MINUTE;
    1457              :         }
    1458              :         /* DAY TO SECOND */
    1459           63 :         else if (range == (INTERVAL_MASK(DAY) |
    1460              :                            INTERVAL_MASK(HOUR) |
    1461              :                            INTERVAL_MASK(MINUTE) |
    1462              :                            INTERVAL_MASK(SECOND)))
    1463              :         {
    1464              :             /* fractional-second rounding will be dealt with below */
    1465              :         }
    1466              :         /* HOUR TO MINUTE */
    1467           45 :         else if (range == (INTERVAL_MASK(HOUR) |
    1468              :                            INTERVAL_MASK(MINUTE)))
    1469              :         {
    1470            6 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1471              :                 USECS_PER_MINUTE;
    1472              :         }
    1473              :         /* HOUR TO SECOND */
    1474           39 :         else if (range == (INTERVAL_MASK(HOUR) |
    1475              :                            INTERVAL_MASK(MINUTE) |
    1476              :                            INTERVAL_MASK(SECOND)))
    1477              :         {
    1478              :             /* fractional-second rounding will be dealt with below */
    1479              :         }
    1480              :         /* MINUTE TO SECOND */
    1481           27 :         else if (range == (INTERVAL_MASK(MINUTE) |
    1482              :                            INTERVAL_MASK(SECOND)))
    1483              :         {
    1484              :             /* fractional-second rounding will be dealt with below */
    1485              :         }
    1486              :         else
    1487            0 :             elog(ERROR, "unrecognized interval typmod: %d", typmod);
    1488              : 
    1489              :         /* Need to adjust sub-second precision? */
    1490          231 :         if (precision != INTERVAL_FULL_PRECISION)
    1491              :         {
    1492           39 :             if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
    1493            0 :                 ereturn(escontext, false,
    1494              :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1495              :                          errmsg("interval(%d) precision must be between %d and %d",
    1496              :                                 precision, 0, MAX_INTERVAL_PRECISION)));
    1497              : 
    1498           39 :             if (interval->time >= INT64CONST(0))
    1499              :             {
    1500           36 :                 if (pg_add_s64_overflow(interval->time,
    1501           36 :                                         IntervalOffsets[precision],
    1502           36 :                                         &interval->time))
    1503            3 :                     ereturn(escontext, false,
    1504              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1505              :                              errmsg("interval out of range")));
    1506           33 :                 interval->time -= interval->time % IntervalScales[precision];
    1507              :             }
    1508              :             else
    1509              :             {
    1510            3 :                 if (pg_sub_s64_overflow(interval->time,
    1511            3 :                                         IntervalOffsets[precision],
    1512            3 :                                         &interval->time))
    1513            3 :                     ereturn(escontext, false,
    1514              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1515              :                              errmsg("interval out of range")));
    1516            0 :                 interval->time -= interval->time % IntervalScales[precision];
    1517              :             }
    1518              :         }
    1519              :     }
    1520              : 
    1521        31778 :     return true;
    1522              : }
    1523              : 
    1524              : /*
    1525              :  * make_interval - numeric Interval constructor
    1526              :  */
    1527              : Datum
    1528           66 : make_interval(PG_FUNCTION_ARGS)
    1529              : {
    1530           66 :     int32       years = PG_GETARG_INT32(0);
    1531           66 :     int32       months = PG_GETARG_INT32(1);
    1532           66 :     int32       weeks = PG_GETARG_INT32(2);
    1533           66 :     int32       days = PG_GETARG_INT32(3);
    1534           66 :     int32       hours = PG_GETARG_INT32(4);
    1535           66 :     int32       mins = PG_GETARG_INT32(5);
    1536           66 :     double      secs = PG_GETARG_FLOAT8(6);
    1537              :     Interval   *result;
    1538              : 
    1539              :     /*
    1540              :      * Reject out-of-range inputs.  We reject any input values that cause
    1541              :      * integer overflow of the corresponding interval fields.
    1542              :      */
    1543           66 :     if (isinf(secs) || isnan(secs))
    1544            6 :         goto out_of_range;
    1545              : 
    1546           60 :     result = palloc_object(Interval);
    1547              : 
    1548              :     /* years and months -> months */
    1549          114 :     if (pg_mul_s32_overflow(years, MONTHS_PER_YEAR, &result->month) ||
    1550           54 :         pg_add_s32_overflow(result->month, months, &result->month))
    1551           12 :         goto out_of_range;
    1552              : 
    1553              :     /* weeks and days -> days */
    1554           90 :     if (pg_mul_s32_overflow(weeks, DAYS_PER_WEEK, &result->day) ||
    1555           42 :         pg_add_s32_overflow(result->day, days, &result->day))
    1556           12 :         goto out_of_range;
    1557              : 
    1558              :     /* hours and mins -> usecs (cannot overflow 64-bit) */
    1559           36 :     result->time = hours * USECS_PER_HOUR + mins * USECS_PER_MINUTE;
    1560              : 
    1561              :     /* secs -> usecs */
    1562           36 :     secs = rint(float8_mul(secs, USECS_PER_SEC));
    1563           60 :     if (!FLOAT8_FITS_IN_INT64(secs) ||
    1564           27 :         pg_add_s64_overflow(result->time, (int64) secs, &result->time))
    1565           12 :         goto out_of_range;
    1566              : 
    1567              :     /* make sure that the result is finite */
    1568           21 :     if (INTERVAL_NOT_FINITE(result))
    1569            0 :         goto out_of_range;
    1570              : 
    1571           21 :     PG_RETURN_INTERVAL_P(result);
    1572              : 
    1573           42 : out_of_range:
    1574           42 :     ereport(ERROR,
    1575              :             errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1576              :             errmsg("interval out of range"));
    1577              : 
    1578              :     PG_RETURN_NULL();           /* keep compiler quiet */
    1579              : }
    1580              : 
    1581              : /* EncodeSpecialTimestamp()
    1582              :  * Convert reserved timestamp data type to string.
    1583              :  */
    1584              : void
    1585          663 : EncodeSpecialTimestamp(Timestamp dt, char *str)
    1586              : {
    1587          663 :     if (TIMESTAMP_IS_NOBEGIN(dt))
    1588          323 :         strcpy(str, EARLY);
    1589          340 :     else if (TIMESTAMP_IS_NOEND(dt))
    1590          340 :         strcpy(str, LATE);
    1591              :     else                        /* shouldn't happen */
    1592            0 :         elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
    1593          663 : }
    1594              : 
    1595              : static void
    1596         1012 : EncodeSpecialInterval(const Interval *interval, char *str)
    1597              : {
    1598         1012 :     if (INTERVAL_IS_NOBEGIN(interval))
    1599          497 :         strcpy(str, EARLY);
    1600          515 :     else if (INTERVAL_IS_NOEND(interval))
    1601          515 :         strcpy(str, LATE);
    1602              :     else                        /* shouldn't happen */
    1603            0 :         elog(ERROR, "invalid argument for EncodeSpecialInterval");
    1604         1012 : }
    1605              : 
    1606              : Datum
    1607        35329 : now(PG_FUNCTION_ARGS)
    1608              : {
    1609        35329 :     PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
    1610              : }
    1611              : 
    1612              : Datum
    1613            3 : statement_timestamp(PG_FUNCTION_ARGS)
    1614              : {
    1615            3 :     PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
    1616              : }
    1617              : 
    1618              : Datum
    1619           14 : clock_timestamp(PG_FUNCTION_ARGS)
    1620              : {
    1621           14 :     PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
    1622              : }
    1623              : 
    1624              : Datum
    1625            0 : pg_postmaster_start_time(PG_FUNCTION_ARGS)
    1626              : {
    1627            0 :     PG_RETURN_TIMESTAMPTZ(PgStartTime);
    1628              : }
    1629              : 
    1630              : Datum
    1631            0 : pg_conf_load_time(PG_FUNCTION_ARGS)
    1632              : {
    1633            0 :     PG_RETURN_TIMESTAMPTZ(PgReloadTime);
    1634              : }
    1635              : 
    1636              : /*
    1637              :  * GetCurrentTimestamp -- get the current operating system time
    1638              :  *
    1639              :  * Result is in the form of a TimestampTz value, and is expressed to the
    1640              :  * full precision of the gettimeofday() syscall
    1641              :  */
    1642              : TimestampTz
    1643      4933481 : GetCurrentTimestamp(void)
    1644              : {
    1645              :     TimestampTz result;
    1646              :     struct timeval tp;
    1647              : 
    1648      4933481 :     gettimeofday(&tp, NULL);
    1649              : 
    1650      4933481 :     result = (TimestampTz) tp.tv_sec -
    1651              :         ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
    1652      4933481 :     result = (result * USECS_PER_SEC) + tp.tv_usec;
    1653              : 
    1654      4933481 :     return result;
    1655              : }
    1656              : 
    1657              : /*
    1658              :  * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
    1659              :  */
    1660              : TimestampTz
    1661          174 : GetSQLCurrentTimestamp(int32 typmod)
    1662              : {
    1663              :     TimestampTz ts;
    1664              : 
    1665          174 :     ts = GetCurrentTransactionStartTimestamp();
    1666          174 :     if (typmod >= 0)
    1667           36 :         AdjustTimestampForTypmod(&ts, typmod, NULL);
    1668          174 :     return ts;
    1669              : }
    1670              : 
    1671              : /*
    1672              :  * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
    1673              :  */
    1674              : Timestamp
    1675           33 : GetSQLLocalTimestamp(int32 typmod)
    1676              : {
    1677              :     Timestamp   ts;
    1678              : 
    1679           33 :     ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
    1680           33 :     if (typmod >= 0)
    1681            3 :         AdjustTimestampForTypmod(&ts, typmod, NULL);
    1682           33 :     return ts;
    1683              : }
    1684              : 
    1685              : /*
    1686              :  * timeofday(*) -- returns the current time as a text.
    1687              :  */
    1688              : Datum
    1689          800 : timeofday(PG_FUNCTION_ARGS)
    1690              : {
    1691              :     struct timeval tp;
    1692              :     char        templ[128];
    1693              :     char        buf[128];
    1694              :     pg_time_t   tt;
    1695              : 
    1696          800 :     gettimeofday(&tp, NULL);
    1697          800 :     tt = (pg_time_t) tp.tv_sec;
    1698          800 :     pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
    1699          800 :                 pg_localtime(&tt, session_timezone));
    1700          800 :     snprintf(buf, sizeof(buf), templ, tp.tv_usec);
    1701              : 
    1702          800 :     PG_RETURN_TEXT_P(cstring_to_text(buf));
    1703              : }
    1704              : 
    1705              : /*
    1706              :  * TimestampDifference -- convert the difference between two timestamps
    1707              :  *      into integer seconds and microseconds
    1708              :  *
    1709              :  * This is typically used to calculate a wait timeout for select(2),
    1710              :  * which explains the otherwise-odd choice of output format.
    1711              :  *
    1712              :  * Both inputs must be ordinary finite timestamps (in current usage,
    1713              :  * they'll be results from GetCurrentTimestamp()).
    1714              :  *
    1715              :  * We expect start_time <= stop_time.  If not, we return zeros,
    1716              :  * since then we're already past the previously determined stop_time.
    1717              :  */
    1718              : void
    1719       667452 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
    1720              :                     long *secs, int *microsecs)
    1721              : {
    1722       667452 :     TimestampTz diff = stop_time - start_time;
    1723              : 
    1724       667452 :     if (diff <= 0)
    1725              :     {
    1726          151 :         *secs = 0;
    1727          151 :         *microsecs = 0;
    1728              :     }
    1729              :     else
    1730              :     {
    1731       667301 :         *secs = (long) (diff / USECS_PER_SEC);
    1732       667301 :         *microsecs = (int) (diff % USECS_PER_SEC);
    1733              :     }
    1734       667452 : }
    1735              : 
    1736              : /*
    1737              :  * TimestampDifferenceMilliseconds -- convert the difference between two
    1738              :  *      timestamps into integer milliseconds
    1739              :  *
    1740              :  * This is typically used to calculate a wait timeout for WaitLatch()
    1741              :  * or a related function.  The choice of "long" as the result type
    1742              :  * is to harmonize with that; furthermore, we clamp the result to at most
    1743              :  * INT_MAX milliseconds, because that's all that WaitLatch() allows.
    1744              :  *
    1745              :  * We expect start_time <= stop_time.  If not, we return zero,
    1746              :  * since then we're already past the previously determined stop_time.
    1747              :  *
    1748              :  * Subtracting finite and infinite timestamps works correctly, returning
    1749              :  * zero or INT_MAX as appropriate.
    1750              :  *
    1751              :  * Note we round up any fractional millisecond, since waiting for just
    1752              :  * less than the intended timeout is undesirable.
    1753              :  */
    1754              : long
    1755       344092 : TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
    1756              : {
    1757              :     TimestampTz diff;
    1758              : 
    1759              :     /* Deal with zero or negative elapsed time quickly. */
    1760       344092 :     if (start_time >= stop_time)
    1761           44 :         return 0;
    1762              :     /* To not fail with timestamp infinities, we must detect overflow. */
    1763       344048 :     if (pg_sub_s64_overflow(stop_time, start_time, &diff))
    1764            0 :         return (long) INT_MAX;
    1765       344048 :     if (diff >= (INT_MAX * INT64CONST(1000) - 999))
    1766            0 :         return (long) INT_MAX;
    1767              :     else
    1768       344048 :         return (long) ((diff + 999) / 1000);
    1769              : }
    1770              : 
    1771              : /*
    1772              :  * TimestampDifferenceExceeds -- report whether the difference between two
    1773              :  *      timestamps is >= a threshold (expressed in milliseconds)
    1774              :  *
    1775              :  * Both inputs must be ordinary finite timestamps (in current usage,
    1776              :  * they'll be results from GetCurrentTimestamp()).
    1777              :  */
    1778              : bool
    1779       675296 : TimestampDifferenceExceeds(TimestampTz start_time,
    1780              :                            TimestampTz stop_time,
    1781              :                            int msec)
    1782              : {
    1783       675296 :     TimestampTz diff = stop_time - start_time;
    1784              : 
    1785       675296 :     return (diff >= msec * INT64CONST(1000));
    1786              : }
    1787              : 
    1788              : /*
    1789              :  * Check if the difference between two timestamps is >= a given
    1790              :  * threshold (expressed in seconds).
    1791              :  */
    1792              : bool
    1793            0 : TimestampDifferenceExceedsSeconds(TimestampTz start_time,
    1794              :                                   TimestampTz stop_time,
    1795              :                                   int threshold_sec)
    1796              : {
    1797              :     long        secs;
    1798              :     int         usecs;
    1799              : 
    1800              :     /* Calculate the difference in seconds */
    1801            0 :     TimestampDifference(start_time, stop_time, &secs, &usecs);
    1802              : 
    1803            0 :     return (secs >= threshold_sec);
    1804              : }
    1805              : 
    1806              : /*
    1807              :  * Convert a time_t to TimestampTz.
    1808              :  *
    1809              :  * We do not use time_t internally in Postgres, but this is provided for use
    1810              :  * by functions that need to interpret, say, a stat(2) result.
    1811              :  *
    1812              :  * To avoid having the function's ABI vary depending on the width of time_t,
    1813              :  * we declare the argument as pg_time_t, which is cast-compatible with
    1814              :  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
    1815              :  * This detail should be invisible to callers, at least at source code level.
    1816              :  */
    1817              : TimestampTz
    1818        21291 : time_t_to_timestamptz(pg_time_t tm)
    1819              : {
    1820              :     TimestampTz result;
    1821              : 
    1822        21291 :     result = (TimestampTz) tm -
    1823              :         ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
    1824        21291 :     result *= USECS_PER_SEC;
    1825              : 
    1826        21291 :     return result;
    1827              : }
    1828              : 
    1829              : /*
    1830              :  * Convert a TimestampTz to time_t.
    1831              :  *
    1832              :  * This too is just marginally useful, but some places need it.
    1833              :  *
    1834              :  * To avoid having the function's ABI vary depending on the width of time_t,
    1835              :  * we declare the result as pg_time_t, which is cast-compatible with
    1836              :  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
    1837              :  * This detail should be invisible to callers, at least at source code level.
    1838              :  */
    1839              : pg_time_t
    1840        25420 : timestamptz_to_time_t(TimestampTz t)
    1841              : {
    1842              :     pg_time_t   result;
    1843              : 
    1844        25420 :     result = (pg_time_t) (t / USECS_PER_SEC +
    1845              :                           ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
    1846              : 
    1847        25420 :     return result;
    1848              : }
    1849              : 
    1850              : /*
    1851              :  * Produce a C-string representation of a TimestampTz.
    1852              :  *
    1853              :  * This is mostly for use in emitting messages.  The primary difference
    1854              :  * from timestamptz_out is that we force the output format to ISO.  Note
    1855              :  * also that the result is in a static buffer, not pstrdup'd.
    1856              :  *
    1857              :  * See also pg_strftime.
    1858              :  */
    1859              : const char *
    1860         1689 : timestamptz_to_str(TimestampTz t)
    1861              : {
    1862              :     static char buf[MAXDATELEN + 1];
    1863              :     int         tz;
    1864              :     struct pg_tm tt,
    1865         1689 :                *tm = &tt;
    1866              :     fsec_t      fsec;
    1867              :     const char *tzn;
    1868              : 
    1869         1689 :     if (TIMESTAMP_NOT_FINITE(t))
    1870            0 :         EncodeSpecialTimestamp(t, buf);
    1871         1689 :     else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
    1872         1689 :         EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
    1873              :     else
    1874            0 :         strlcpy(buf, "(timestamp out of range)", sizeof(buf));
    1875              : 
    1876         1689 :     return buf;
    1877              : }
    1878              : 
    1879              : 
    1880              : void
    1881       156502 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
    1882              : {
    1883              :     TimeOffset  time;
    1884              : 
    1885       156502 :     time = jd;
    1886              : 
    1887       156502 :     *hour = time / USECS_PER_HOUR;
    1888       156502 :     time -= (*hour) * USECS_PER_HOUR;
    1889       156502 :     *min = time / USECS_PER_MINUTE;
    1890       156502 :     time -= (*min) * USECS_PER_MINUTE;
    1891       156502 :     *sec = time / USECS_PER_SEC;
    1892       156502 :     *fsec = time - (*sec * USECS_PER_SEC);
    1893       156502 : }                               /* dt2time() */
    1894              : 
    1895              : 
    1896              : /*
    1897              :  * timestamp2tm() - Convert timestamp data type to POSIX time structure.
    1898              :  *
    1899              :  * Note that year is _not_ 1900-based, but is an explicit full value.
    1900              :  * Also, month is one-based, _not_ zero-based.
    1901              :  * Returns:
    1902              :  *   0 on success
    1903              :  *  -1 on out of range
    1904              :  *
    1905              :  * If attimezone is NULL, the global timezone setting will be used.
    1906              :  */
    1907              : int
    1908       156496 : timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
    1909              : {
    1910              :     Timestamp   date;
    1911              :     Timestamp   time;
    1912              :     pg_time_t   utime;
    1913              : 
    1914              :     /* Use session timezone if caller asks for default */
    1915       156496 :     if (attimezone == NULL)
    1916       120075 :         attimezone = session_timezone;
    1917              : 
    1918       156496 :     time = dt;
    1919       156496 :     TMODULO(time, date, USECS_PER_DAY);
    1920              : 
    1921       156496 :     if (time < INT64CONST(0))
    1922              :     {
    1923        51123 :         time += USECS_PER_DAY;
    1924        51123 :         date -= 1;
    1925              :     }
    1926              : 
    1927              :     /* add offset to go from J2000 back to standard Julian date */
    1928       156496 :     date += POSTGRES_EPOCH_JDATE;
    1929              : 
    1930              :     /* Julian day routine does not work for negative Julian days */
    1931       156496 :     if (date < 0 || date > (Timestamp) INT_MAX)
    1932            0 :         return -1;
    1933              : 
    1934       156496 :     j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1935       156496 :     dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
    1936              : 
    1937              :     /* Done if no TZ conversion wanted */
    1938       156496 :     if (tzp == NULL)
    1939              :     {
    1940        43052 :         tm->tm_isdst = -1;
    1941        43052 :         tm->tm_gmtoff = 0;
    1942        43052 :         tm->tm_zone = NULL;
    1943        43052 :         if (tzn != NULL)
    1944            0 :             *tzn = NULL;
    1945        43052 :         return 0;
    1946              :     }
    1947              : 
    1948              :     /*
    1949              :      * If the time falls within the range of pg_time_t, use pg_localtime() to
    1950              :      * rotate to the local time zone.
    1951              :      *
    1952              :      * First, convert to an integral timestamp, avoiding possibly
    1953              :      * platform-specific roundoff-in-wrong-direction errors, and adjust to
    1954              :      * Unix epoch.  Then see if we can convert to pg_time_t without loss. This
    1955              :      * coding avoids hardwiring any assumptions about the width of pg_time_t,
    1956              :      * so it should behave sanely on machines without int64.
    1957              :      */
    1958       113444 :     dt = (dt - *fsec) / USECS_PER_SEC +
    1959              :         (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
    1960       113444 :     utime = (pg_time_t) dt;
    1961       113444 :     if ((Timestamp) utime == dt)
    1962              :     {
    1963       113444 :         struct pg_tm *tx = pg_localtime(&utime, attimezone);
    1964              : 
    1965       113444 :         tm->tm_year = tx->tm_year + 1900;
    1966       113444 :         tm->tm_mon = tx->tm_mon + 1;
    1967       113444 :         tm->tm_mday = tx->tm_mday;
    1968       113444 :         tm->tm_hour = tx->tm_hour;
    1969       113444 :         tm->tm_min = tx->tm_min;
    1970       113444 :         tm->tm_sec = tx->tm_sec;
    1971       113444 :         tm->tm_isdst = tx->tm_isdst;
    1972       113444 :         tm->tm_gmtoff = tx->tm_gmtoff;
    1973       113444 :         tm->tm_zone = tx->tm_zone;
    1974       113444 :         *tzp = -tm->tm_gmtoff;
    1975       113444 :         if (tzn != NULL)
    1976        43882 :             *tzn = tm->tm_zone;
    1977              :     }
    1978              :     else
    1979              :     {
    1980              :         /*
    1981              :          * When out of range of pg_time_t, treat as GMT
    1982              :          */
    1983            0 :         *tzp = 0;
    1984              :         /* Mark this as *no* time zone available */
    1985            0 :         tm->tm_isdst = -1;
    1986            0 :         tm->tm_gmtoff = 0;
    1987            0 :         tm->tm_zone = NULL;
    1988            0 :         if (tzn != NULL)
    1989            0 :             *tzn = NULL;
    1990              :     }
    1991              : 
    1992       113444 :     return 0;
    1993              : }
    1994              : 
    1995              : 
    1996              : /* tm2timestamp()
    1997              :  * Convert a tm structure to a timestamp data type.
    1998              :  * Note that year is _not_ 1900-based, but is an explicit full value.
    1999              :  * Also, month is one-based, _not_ zero-based.
    2000              :  *
    2001              :  * Returns -1 on failure (value out of range).
    2002              :  */
    2003              : int
    2004       110687 : tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
    2005              : {
    2006              :     TimeOffset  date;
    2007              :     TimeOffset  time;
    2008              : 
    2009              :     /* Prevent overflow in Julian-day routines */
    2010       110687 :     if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
    2011              :     {
    2012            6 :         *result = 0;            /* keep compiler quiet */
    2013            6 :         return -1;
    2014              :     }
    2015              : 
    2016       110681 :     date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
    2017       110681 :     time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
    2018              : 
    2019       110681 :     if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, result) ||
    2020              :                  pg_add_s64_overflow(*result, time, result)))
    2021              :     {
    2022            3 :         *result = 0;            /* keep compiler quiet */
    2023            3 :         return -1;
    2024              :     }
    2025       110678 :     if (tzp != NULL)
    2026        52317 :         *result = dt2local(*result, -(*tzp));
    2027              : 
    2028              :     /* final range check catches just-out-of-range timestamps */
    2029       110678 :     if (!IS_VALID_TIMESTAMP(*result))
    2030              :     {
    2031           14 :         *result = 0;            /* keep compiler quiet */
    2032           14 :         return -1;
    2033              :     }
    2034              : 
    2035       110664 :     return 0;
    2036              : }
    2037              : 
    2038              : 
    2039              : /* interval2itm()
    2040              :  * Convert an Interval to a pg_itm structure.
    2041              :  * Note: overflow is not possible, because the pg_itm fields are
    2042              :  * wide enough for all possible conversion results.
    2043              :  */
    2044              : void
    2045         8205 : interval2itm(Interval span, struct pg_itm *itm)
    2046              : {
    2047              :     TimeOffset  time;
    2048              :     TimeOffset  tfrac;
    2049              : 
    2050         8205 :     itm->tm_year = span.month / MONTHS_PER_YEAR;
    2051         8205 :     itm->tm_mon = span.month % MONTHS_PER_YEAR;
    2052         8205 :     itm->tm_mday = span.day;
    2053         8205 :     time = span.time;
    2054              : 
    2055         8205 :     tfrac = time / USECS_PER_HOUR;
    2056         8205 :     time -= tfrac * USECS_PER_HOUR;
    2057         8205 :     itm->tm_hour = tfrac;
    2058         8205 :     tfrac = time / USECS_PER_MINUTE;
    2059         8205 :     time -= tfrac * USECS_PER_MINUTE;
    2060         8205 :     itm->tm_min = (int) tfrac;
    2061         8205 :     tfrac = time / USECS_PER_SEC;
    2062         8205 :     time -= tfrac * USECS_PER_SEC;
    2063         8205 :     itm->tm_sec = (int) tfrac;
    2064         8205 :     itm->tm_usec = (int) time;
    2065         8205 : }
    2066              : 
    2067              : /* itm2interval()
    2068              :  * Convert a pg_itm structure to an Interval.
    2069              :  * Returns 0 if OK, -1 on overflow.
    2070              :  *
    2071              :  * This is for use in computations expected to produce finite results.  Any
    2072              :  * inputs that lead to infinite results are treated as overflows.
    2073              :  */
    2074              : int
    2075            0 : itm2interval(struct pg_itm *itm, Interval *span)
    2076              : {
    2077            0 :     int64       total_months = (int64) itm->tm_year * MONTHS_PER_YEAR + itm->tm_mon;
    2078              : 
    2079            0 :     if (total_months > INT_MAX || total_months < INT_MIN)
    2080            0 :         return -1;
    2081            0 :     span->month = (int32) total_months;
    2082            0 :     span->day = itm->tm_mday;
    2083            0 :     if (pg_mul_s64_overflow(itm->tm_hour, USECS_PER_HOUR,
    2084            0 :                             &span->time))
    2085            0 :         return -1;
    2086              :     /* tm_min, tm_sec are 32 bits, so intermediate products can't overflow */
    2087            0 :     if (pg_add_s64_overflow(span->time, itm->tm_min * USECS_PER_MINUTE,
    2088            0 :                             &span->time))
    2089            0 :         return -1;
    2090            0 :     if (pg_add_s64_overflow(span->time, itm->tm_sec * USECS_PER_SEC,
    2091            0 :                             &span->time))
    2092            0 :         return -1;
    2093            0 :     if (pg_add_s64_overflow(span->time, itm->tm_usec,
    2094            0 :                             &span->time))
    2095            0 :         return -1;
    2096            0 :     if (INTERVAL_NOT_FINITE(span))
    2097            0 :         return -1;
    2098            0 :     return 0;
    2099              : }
    2100              : 
    2101              : /* itmin2interval()
    2102              :  * Convert a pg_itm_in structure to an Interval.
    2103              :  * Returns 0 if OK, -1 on overflow.
    2104              :  *
    2105              :  * Note: if the result is infinite, it is not treated as an overflow.  This
    2106              :  * avoids any dump/reload hazards from pre-17 databases that do not support
    2107              :  * infinite intervals, but do allow finite intervals with all fields set to
    2108              :  * INT_MIN/INT_MAX (outside the documented range).  Such intervals will be
    2109              :  * silently converted to +/-infinity.  This may not be ideal, but seems
    2110              :  * preferable to failure, and ought to be pretty unlikely in practice.
    2111              :  */
    2112              : int
    2113        38944 : itmin2interval(struct pg_itm_in *itm_in, Interval *span)
    2114              : {
    2115        38944 :     int64       total_months = (int64) itm_in->tm_year * MONTHS_PER_YEAR + itm_in->tm_mon;
    2116              : 
    2117        38944 :     if (total_months > INT_MAX || total_months < INT_MIN)
    2118            9 :         return -1;
    2119        38935 :     span->month = (int32) total_months;
    2120        38935 :     span->day = itm_in->tm_mday;
    2121        38935 :     span->time = itm_in->tm_usec;
    2122        38935 :     return 0;
    2123              : }
    2124              : 
    2125              : static TimeOffset
    2126       110681 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
    2127              : {
    2128       110681 :     return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
    2129              : }
    2130              : 
    2131              : static Timestamp
    2132        60649 : dt2local(Timestamp dt, int timezone)
    2133              : {
    2134        60649 :     dt -= (timezone * USECS_PER_SEC);
    2135        60649 :     return dt;
    2136              : }
    2137              : 
    2138              : 
    2139              : /*****************************************************************************
    2140              :  *   PUBLIC ROUTINES                                                         *
    2141              :  *****************************************************************************/
    2142              : 
    2143              : 
    2144              : Datum
    2145            0 : timestamp_finite(PG_FUNCTION_ARGS)
    2146              : {
    2147            0 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    2148              : 
    2149            0 :     PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
    2150              : }
    2151              : 
    2152              : Datum
    2153          159 : interval_finite(PG_FUNCTION_ARGS)
    2154              : {
    2155          159 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    2156              : 
    2157          159 :     PG_RETURN_BOOL(!INTERVAL_NOT_FINITE(interval));
    2158              : }
    2159              : 
    2160              : 
    2161              : /*----------------------------------------------------------
    2162              :  *  Relational operators for timestamp.
    2163              :  *---------------------------------------------------------*/
    2164              : 
    2165              : void
    2166        14188 : GetEpochTime(struct pg_tm *tm)
    2167              : {
    2168              :     struct pg_tm *t0;
    2169        14188 :     pg_time_t   epoch = 0;
    2170              : 
    2171        14188 :     t0 = pg_gmtime(&epoch);
    2172              : 
    2173        14188 :     if (t0 == NULL)
    2174            0 :         elog(ERROR, "could not convert epoch to timestamp: %m");
    2175              : 
    2176        14188 :     tm->tm_year = t0->tm_year;
    2177        14188 :     tm->tm_mon = t0->tm_mon;
    2178        14188 :     tm->tm_mday = t0->tm_mday;
    2179        14188 :     tm->tm_hour = t0->tm_hour;
    2180        14188 :     tm->tm_min = t0->tm_min;
    2181        14188 :     tm->tm_sec = t0->tm_sec;
    2182              : 
    2183        14188 :     tm->tm_year += 1900;
    2184        14188 :     tm->tm_mon++;
    2185        14188 : }
    2186              : 
    2187              : Timestamp
    2188        14185 : SetEpochTimestamp(void)
    2189              : {
    2190              :     Timestamp   dt;
    2191              :     struct pg_tm tt,
    2192        14185 :                *tm = &tt;
    2193              : 
    2194        14185 :     GetEpochTime(tm);
    2195              :     /* we don't bother to test for failure ... */
    2196        14185 :     tm2timestamp(tm, 0, NULL, &dt);
    2197              : 
    2198        14185 :     return dt;
    2199              : }                               /* SetEpochTimestamp() */
    2200              : 
    2201              : /*
    2202              :  * We are currently sharing some code between timestamp and timestamptz.
    2203              :  * The comparison functions are among them. - thomas 2001-09-25
    2204              :  *
    2205              :  *      timestamp_relop - is timestamp1 relop timestamp2
    2206              :  */
    2207              : int
    2208       233812 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
    2209              : {
    2210       233812 :     return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
    2211              : }
    2212              : 
    2213              : Datum
    2214        14379 : timestamp_eq(PG_FUNCTION_ARGS)
    2215              : {
    2216        14379 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2217        14379 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2218              : 
    2219        14379 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
    2220              : }
    2221              : 
    2222              : Datum
    2223          393 : timestamp_ne(PG_FUNCTION_ARGS)
    2224              : {
    2225          393 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2226          393 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2227              : 
    2228          393 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
    2229              : }
    2230              : 
    2231              : Datum
    2232        88962 : timestamp_lt(PG_FUNCTION_ARGS)
    2233              : {
    2234        88962 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2235        88962 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2236              : 
    2237        88962 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
    2238              : }
    2239              : 
    2240              : Datum
    2241        49716 : timestamp_gt(PG_FUNCTION_ARGS)
    2242              : {
    2243        49716 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2244        49716 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2245              : 
    2246        49716 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
    2247              : }
    2248              : 
    2249              : Datum
    2250         9466 : timestamp_le(PG_FUNCTION_ARGS)
    2251              : {
    2252         9466 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2253         9466 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2254              : 
    2255         9466 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
    2256              : }
    2257              : 
    2258              : Datum
    2259         9776 : timestamp_ge(PG_FUNCTION_ARGS)
    2260              : {
    2261         9776 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2262         9776 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2263              : 
    2264         9776 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
    2265              : }
    2266              : 
    2267              : Datum
    2268        20907 : timestamp_cmp(PG_FUNCTION_ARGS)
    2269              : {
    2270        20907 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2271        20907 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2272              : 
    2273        20907 :     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
    2274              : }
    2275              : 
    2276              : Datum
    2277          287 : timestamp_sortsupport(PG_FUNCTION_ARGS)
    2278              : {
    2279          287 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
    2280              : 
    2281          287 :     ssup->comparator = ssup_datum_signed_cmp;
    2282          287 :     PG_RETURN_VOID();
    2283              : }
    2284              : 
    2285              : /* note: this is used for timestamptz also */
    2286              : static Datum
    2287            0 : timestamp_decrement(Relation rel, Datum existing, bool *underflow)
    2288              : {
    2289            0 :     Timestamp   texisting = DatumGetTimestamp(existing);
    2290              : 
    2291            0 :     if (texisting == PG_INT64_MIN)
    2292              :     {
    2293              :         /* return value is undefined */
    2294            0 :         *underflow = true;
    2295            0 :         return (Datum) 0;
    2296              :     }
    2297              : 
    2298            0 :     *underflow = false;
    2299            0 :     return TimestampGetDatum(texisting - 1);
    2300              : }
    2301              : 
    2302              : /* note: this is used for timestamptz also */
    2303              : static Datum
    2304            0 : timestamp_increment(Relation rel, Datum existing, bool *overflow)
    2305              : {
    2306            0 :     Timestamp   texisting = DatumGetTimestamp(existing);
    2307              : 
    2308            0 :     if (texisting == PG_INT64_MAX)
    2309              :     {
    2310              :         /* return value is undefined */
    2311            0 :         *overflow = true;
    2312            0 :         return (Datum) 0;
    2313              :     }
    2314              : 
    2315            0 :     *overflow = false;
    2316            0 :     return TimestampGetDatum(texisting + 1);
    2317              : }
    2318              : 
    2319              : Datum
    2320            0 : timestamp_skipsupport(PG_FUNCTION_ARGS)
    2321              : {
    2322            0 :     SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
    2323              : 
    2324            0 :     sksup->decrement = timestamp_decrement;
    2325            0 :     sksup->increment = timestamp_increment;
    2326            0 :     sksup->low_elem = TimestampGetDatum(PG_INT64_MIN);
    2327            0 :     sksup->high_elem = TimestampGetDatum(PG_INT64_MAX);
    2328              : 
    2329            0 :     PG_RETURN_VOID();
    2330              : }
    2331              : 
    2332              : Datum
    2333         3247 : timestamp_hash(PG_FUNCTION_ARGS)
    2334              : {
    2335         3247 :     return hashint8(fcinfo);
    2336              : }
    2337              : 
    2338              : Datum
    2339           30 : timestamp_hash_extended(PG_FUNCTION_ARGS)
    2340              : {
    2341           30 :     return hashint8extended(fcinfo);
    2342              : }
    2343              : 
    2344              : Datum
    2345            0 : timestamptz_hash(PG_FUNCTION_ARGS)
    2346              : {
    2347            0 :     return hashint8(fcinfo);
    2348              : }
    2349              : 
    2350              : Datum
    2351            0 : timestamptz_hash_extended(PG_FUNCTION_ARGS)
    2352              : {
    2353            0 :     return hashint8extended(fcinfo);
    2354              : }
    2355              : 
    2356              : /*
    2357              :  * Cross-type comparison functions for timestamp vs timestamptz
    2358              :  */
    2359              : 
    2360              : int32
    2361         8037 : timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
    2362              : {
    2363              :     TimestampTz dt1;
    2364         8037 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    2365              : 
    2366         8037 :     dt1 = timestamp2timestamptz_safe(timestampVal, (Node *) &escontext);
    2367         8037 :     if (escontext.error_occurred)
    2368              :     {
    2369            6 :         if (TIMESTAMP_IS_NOEND(dt1))
    2370              :         {
    2371              :             /* dt1 is larger than any finite timestamp, but less than infinity */
    2372            0 :             return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
    2373              :         }
    2374            6 :         if (TIMESTAMP_IS_NOBEGIN(dt1))
    2375              :         {
    2376              :             /* dt1 is less than any finite timestamp, but more than -infinity */
    2377            6 :             return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
    2378              :         }
    2379              :     }
    2380              : 
    2381         8031 :     return timestamptz_cmp_internal(dt1, dt2);
    2382              : }
    2383              : 
    2384              : Datum
    2385          906 : timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
    2386              : {
    2387          906 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2388          906 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2389              : 
    2390          906 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) == 0);
    2391              : }
    2392              : 
    2393              : Datum
    2394            0 : timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
    2395              : {
    2396            0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2397            0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2398              : 
    2399            0 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) != 0);
    2400              : }
    2401              : 
    2402              : Datum
    2403         1602 : timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
    2404              : {
    2405         1602 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2406         1602 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2407              : 
    2408         1602 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) < 0);
    2409              : }
    2410              : 
    2411              : Datum
    2412         1599 : timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
    2413              : {
    2414         1599 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2415         1599 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2416              : 
    2417         1599 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) > 0);
    2418              : }
    2419              : 
    2420              : Datum
    2421         1899 : timestamp_le_timestamptz(PG_FUNCTION_ARGS)
    2422              : {
    2423         1899 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2424         1899 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2425              : 
    2426         1899 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) <= 0);
    2427              : }
    2428              : 
    2429              : Datum
    2430         1752 : timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
    2431              : {
    2432         1752 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2433         1752 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2434              : 
    2435         1752 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) >= 0);
    2436              : }
    2437              : 
    2438              : Datum
    2439           53 : timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
    2440              : {
    2441           53 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2442           53 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2443              : 
    2444           53 :     PG_RETURN_INT32(timestamp_cmp_timestamptz_internal(timestampVal, dt2));
    2445              : }
    2446              : 
    2447              : Datum
    2448            0 : timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
    2449              : {
    2450            0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2451            0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2452              : 
    2453            0 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) == 0);
    2454              : }
    2455              : 
    2456              : Datum
    2457           48 : timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
    2458              : {
    2459           48 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2460           48 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2461              : 
    2462           48 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) != 0);
    2463              : }
    2464              : 
    2465              : Datum
    2466            0 : timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
    2467              : {
    2468            0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2469            0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2470              : 
    2471            0 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) > 0);
    2472              : }
    2473              : 
    2474              : Datum
    2475            0 : timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
    2476              : {
    2477            0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2478            0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2479              : 
    2480            0 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) < 0);
    2481              : }
    2482              : 
    2483              : Datum
    2484            0 : timestamptz_le_timestamp(PG_FUNCTION_ARGS)
    2485              : {
    2486            0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2487            0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2488              : 
    2489            0 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) >= 0);
    2490              : }
    2491              : 
    2492              : Datum
    2493            3 : timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
    2494              : {
    2495            3 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2496            3 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2497              : 
    2498            3 :     PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) <= 0);
    2499              : }
    2500              : 
    2501              : Datum
    2502           67 : timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
    2503              : {
    2504           67 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2505           67 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2506              : 
    2507           67 :     PG_RETURN_INT32(-timestamp_cmp_timestamptz_internal(timestampVal, dt1));
    2508              : }
    2509              : 
    2510              : 
    2511              : /*
    2512              :  *      interval_relop  - is interval1 relop interval2
    2513              :  *
    2514              :  * Interval comparison is based on converting interval values to a linear
    2515              :  * representation expressed in the units of the time field (microseconds,
    2516              :  * in the case of integer timestamps) with days assumed to be always 24 hours
    2517              :  * and months assumed to be always 30 days.  To avoid overflow, we need a
    2518              :  * wider-than-int64 datatype for the linear representation, so use INT128.
    2519              :  */
    2520              : 
    2521              : static inline INT128
    2522       138213 : interval_cmp_value(const Interval *interval)
    2523              : {
    2524              :     INT128      span;
    2525              :     int64       days;
    2526              : 
    2527              :     /*
    2528              :      * Combine the month and day fields into an integral number of days.
    2529              :      * Because the inputs are int32, int64 arithmetic suffices here.
    2530              :      */
    2531       138213 :     days = interval->month * INT64CONST(30);
    2532       138213 :     days += interval->day;
    2533              : 
    2534              :     /* Widen time field to 128 bits */
    2535       138213 :     span = int64_to_int128(interval->time);
    2536              : 
    2537              :     /* Scale up days to microseconds, forming a 128-bit product */
    2538       138213 :     int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
    2539              : 
    2540       138213 :     return span;
    2541              : }
    2542              : 
    2543              : static int
    2544        67300 : interval_cmp_internal(const Interval *interval1, const Interval *interval2)
    2545              : {
    2546        67300 :     INT128      span1 = interval_cmp_value(interval1);
    2547        67300 :     INT128      span2 = interval_cmp_value(interval2);
    2548              : 
    2549        67300 :     return int128_compare(span1, span2);
    2550              : }
    2551              : 
    2552              : static int
    2553         2444 : interval_sign(const Interval *interval)
    2554              : {
    2555         2444 :     INT128      span = interval_cmp_value(interval);
    2556         2444 :     INT128      zero = int64_to_int128(0);
    2557              : 
    2558         2444 :     return int128_compare(span, zero);
    2559              : }
    2560              : 
    2561              : Datum
    2562         7143 : interval_eq(PG_FUNCTION_ARGS)
    2563              : {
    2564         7143 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2565         7143 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2566              : 
    2567         7143 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
    2568              : }
    2569              : 
    2570              : Datum
    2571           54 : interval_ne(PG_FUNCTION_ARGS)
    2572              : {
    2573           54 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2574           54 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2575              : 
    2576           54 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
    2577              : }
    2578              : 
    2579              : Datum
    2580        15484 : interval_lt(PG_FUNCTION_ARGS)
    2581              : {
    2582        15484 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2583        15484 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2584              : 
    2585        15484 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
    2586              : }
    2587              : 
    2588              : Datum
    2589         5663 : interval_gt(PG_FUNCTION_ARGS)
    2590              : {
    2591         5663 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2592         5663 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2593              : 
    2594         5663 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
    2595              : }
    2596              : 
    2597              : Datum
    2598         3207 : interval_le(PG_FUNCTION_ARGS)
    2599              : {
    2600         3207 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2601         3207 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2602              : 
    2603         3207 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
    2604              : }
    2605              : 
    2606              : Datum
    2607         2964 : interval_ge(PG_FUNCTION_ARGS)
    2608              : {
    2609         2964 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2610         2964 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2611              : 
    2612         2964 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
    2613              : }
    2614              : 
    2615              : Datum
    2616        32341 : interval_cmp(PG_FUNCTION_ARGS)
    2617              : {
    2618        32341 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2619        32341 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2620              : 
    2621        32341 :     PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
    2622              : }
    2623              : 
    2624              : /*
    2625              :  * Hashing for intervals
    2626              :  *
    2627              :  * We must produce equal hashvals for values that interval_cmp_internal()
    2628              :  * considers equal.  So, compute the net span the same way it does,
    2629              :  * and then hash that.
    2630              :  */
    2631              : Datum
    2632         1139 : interval_hash(PG_FUNCTION_ARGS)
    2633              : {
    2634         1139 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    2635         1139 :     INT128      span = interval_cmp_value(interval);
    2636              :     int64       span64;
    2637              : 
    2638              :     /*
    2639              :      * Use only the least significant 64 bits for hashing.  The upper 64 bits
    2640              :      * seldom add any useful information, and besides we must do it like this
    2641              :      * for compatibility with hashes calculated before use of INT128 was
    2642              :      * introduced.
    2643              :      */
    2644         1139 :     span64 = int128_to_int64(span);
    2645              : 
    2646         1139 :     return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
    2647              : }
    2648              : 
    2649              : Datum
    2650           30 : interval_hash_extended(PG_FUNCTION_ARGS)
    2651              : {
    2652           30 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    2653           30 :     INT128      span = interval_cmp_value(interval);
    2654              :     int64       span64;
    2655              : 
    2656              :     /* Same approach as interval_hash */
    2657           30 :     span64 = int128_to_int64(span);
    2658              : 
    2659           30 :     return DirectFunctionCall2(hashint8extended, Int64GetDatumFast(span64),
    2660              :                                PG_GETARG_DATUM(1));
    2661              : }
    2662              : 
    2663              : /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
    2664              :  *
    2665              :  * Algorithm is per SQL spec.  This is much harder than you'd think
    2666              :  * because the spec requires us to deliver a non-null answer in some cases
    2667              :  * where some of the inputs are null.
    2668              :  */
    2669              : Datum
    2670           36 : overlaps_timestamp(PG_FUNCTION_ARGS)
    2671              : {
    2672              :     /*
    2673              :      * The arguments are Timestamps, but we leave them as generic Datums to
    2674              :      * avoid unnecessary conversions between value and reference forms --- not
    2675              :      * to mention possible dereferences of null pointers.
    2676              :      */
    2677           36 :     Datum       ts1 = PG_GETARG_DATUM(0);
    2678           36 :     Datum       te1 = PG_GETARG_DATUM(1);
    2679           36 :     Datum       ts2 = PG_GETARG_DATUM(2);
    2680           36 :     Datum       te2 = PG_GETARG_DATUM(3);
    2681           36 :     bool        ts1IsNull = PG_ARGISNULL(0);
    2682           36 :     bool        te1IsNull = PG_ARGISNULL(1);
    2683           36 :     bool        ts2IsNull = PG_ARGISNULL(2);
    2684           36 :     bool        te2IsNull = PG_ARGISNULL(3);
    2685              : 
    2686              : #define TIMESTAMP_GT(t1,t2) \
    2687              :     DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
    2688              : #define TIMESTAMP_LT(t1,t2) \
    2689              :     DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
    2690              : 
    2691              :     /*
    2692              :      * If both endpoints of interval 1 are null, the result is null (unknown).
    2693              :      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
    2694              :      * take ts1 as the lesser endpoint.
    2695              :      */
    2696           36 :     if (ts1IsNull)
    2697              :     {
    2698            0 :         if (te1IsNull)
    2699            0 :             PG_RETURN_NULL();
    2700              :         /* swap null for non-null */
    2701            0 :         ts1 = te1;
    2702            0 :         te1IsNull = true;
    2703              :     }
    2704           36 :     else if (!te1IsNull)
    2705              :     {
    2706           36 :         if (TIMESTAMP_GT(ts1, te1))
    2707              :         {
    2708            0 :             Datum       tt = ts1;
    2709              : 
    2710            0 :             ts1 = te1;
    2711            0 :             te1 = tt;
    2712              :         }
    2713              :     }
    2714              : 
    2715              :     /* Likewise for interval 2. */
    2716           36 :     if (ts2IsNull)
    2717              :     {
    2718            0 :         if (te2IsNull)
    2719            0 :             PG_RETURN_NULL();
    2720              :         /* swap null for non-null */
    2721            0 :         ts2 = te2;
    2722            0 :         te2IsNull = true;
    2723              :     }
    2724           36 :     else if (!te2IsNull)
    2725              :     {
    2726           36 :         if (TIMESTAMP_GT(ts2, te2))
    2727              :         {
    2728            0 :             Datum       tt = ts2;
    2729              : 
    2730            0 :             ts2 = te2;
    2731            0 :             te2 = tt;
    2732              :         }
    2733              :     }
    2734              : 
    2735              :     /*
    2736              :      * At this point neither ts1 nor ts2 is null, so we can consider three
    2737              :      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
    2738              :      */
    2739           36 :     if (TIMESTAMP_GT(ts1, ts2))
    2740              :     {
    2741              :         /*
    2742              :          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
    2743              :          * in the presence of nulls it's not quite completely so.
    2744              :          */
    2745            0 :         if (te2IsNull)
    2746            0 :             PG_RETURN_NULL();
    2747            0 :         if (TIMESTAMP_LT(ts1, te2))
    2748            0 :             PG_RETURN_BOOL(true);
    2749            0 :         if (te1IsNull)
    2750            0 :             PG_RETURN_NULL();
    2751              : 
    2752              :         /*
    2753              :          * If te1 is not null then we had ts1 <= te1 above, and we just found
    2754              :          * ts1 >= te2, hence te1 >= te2.
    2755              :          */
    2756            0 :         PG_RETURN_BOOL(false);
    2757              :     }
    2758           36 :     else if (TIMESTAMP_LT(ts1, ts2))
    2759              :     {
    2760              :         /* This case is ts2 < te1 OR te2 < te1 */
    2761           30 :         if (te1IsNull)
    2762            0 :             PG_RETURN_NULL();
    2763           30 :         if (TIMESTAMP_LT(ts2, te1))
    2764           12 :             PG_RETURN_BOOL(true);
    2765           18 :         if (te2IsNull)
    2766            0 :             PG_RETURN_NULL();
    2767              : 
    2768              :         /*
    2769              :          * If te2 is not null then we had ts2 <= te2 above, and we just found
    2770              :          * ts2 >= te1, hence te2 >= te1.
    2771              :          */
    2772           18 :         PG_RETURN_BOOL(false);
    2773              :     }
    2774              :     else
    2775              :     {
    2776              :         /*
    2777              :          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
    2778              :          * rather silly way of saying "true if both are non-null, else null".
    2779              :          */
    2780            6 :         if (te1IsNull || te2IsNull)
    2781            0 :             PG_RETURN_NULL();
    2782            6 :         PG_RETURN_BOOL(true);
    2783              :     }
    2784              : 
    2785              : #undef TIMESTAMP_GT
    2786              : #undef TIMESTAMP_LT
    2787              : }
    2788              : 
    2789              : 
    2790              : /*----------------------------------------------------------
    2791              :  *  "Arithmetic" operators on date/times.
    2792              :  *---------------------------------------------------------*/
    2793              : 
    2794              : Datum
    2795            0 : timestamp_smaller(PG_FUNCTION_ARGS)
    2796              : {
    2797            0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2798            0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2799              :     Timestamp   result;
    2800              : 
    2801              :     /* use timestamp_cmp_internal to be sure this agrees with comparisons */
    2802            0 :     if (timestamp_cmp_internal(dt1, dt2) < 0)
    2803            0 :         result = dt1;
    2804              :     else
    2805            0 :         result = dt2;
    2806            0 :     PG_RETURN_TIMESTAMP(result);
    2807              : }
    2808              : 
    2809              : Datum
    2810           42 : timestamp_larger(PG_FUNCTION_ARGS)
    2811              : {
    2812           42 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2813           42 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2814              :     Timestamp   result;
    2815              : 
    2816           42 :     if (timestamp_cmp_internal(dt1, dt2) > 0)
    2817            0 :         result = dt1;
    2818              :     else
    2819           42 :         result = dt2;
    2820           42 :     PG_RETURN_TIMESTAMP(result);
    2821              : }
    2822              : 
    2823              : 
    2824              : Datum
    2825         3227 : timestamp_mi(PG_FUNCTION_ARGS)
    2826              : {
    2827         3227 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2828         3227 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2829              :     Interval   *result;
    2830              : 
    2831         3227 :     result = palloc_object(Interval);
    2832              : 
    2833              :     /*
    2834              :      * Handle infinities.
    2835              :      *
    2836              :      * We treat anything that amounts to "infinity - infinity" as an error,
    2837              :      * since the interval type has nothing equivalent to NaN.
    2838              :      */
    2839         3227 :     if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
    2840              :     {
    2841           42 :         if (TIMESTAMP_IS_NOBEGIN(dt1))
    2842              :         {
    2843           18 :             if (TIMESTAMP_IS_NOBEGIN(dt2))
    2844            6 :                 ereport(ERROR,
    2845              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2846              :                          errmsg("interval out of range")));
    2847              :             else
    2848           12 :                 INTERVAL_NOBEGIN(result);
    2849              :         }
    2850           24 :         else if (TIMESTAMP_IS_NOEND(dt1))
    2851              :         {
    2852           24 :             if (TIMESTAMP_IS_NOEND(dt2))
    2853            6 :                 ereport(ERROR,
    2854              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2855              :                          errmsg("interval out of range")));
    2856              :             else
    2857           18 :                 INTERVAL_NOEND(result);
    2858              :         }
    2859            0 :         else if (TIMESTAMP_IS_NOBEGIN(dt2))
    2860            0 :             INTERVAL_NOEND(result);
    2861              :         else                    /* TIMESTAMP_IS_NOEND(dt2) */
    2862            0 :             INTERVAL_NOBEGIN(result);
    2863              : 
    2864           30 :         PG_RETURN_INTERVAL_P(result);
    2865              :     }
    2866              : 
    2867         3185 :     if (unlikely(pg_sub_s64_overflow(dt1, dt2, &result->time)))
    2868            6 :         ereport(ERROR,
    2869              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2870              :                  errmsg("interval out of range")));
    2871              : 
    2872         3179 :     result->month = 0;
    2873         3179 :     result->day = 0;
    2874              : 
    2875              :     /*----------
    2876              :      *  This is wrong, but removing it breaks a lot of regression tests.
    2877              :      *  For example:
    2878              :      *
    2879              :      *  test=> SET timezone = 'EST5EDT';
    2880              :      *  test=> SELECT
    2881              :      *  test-> ('2005-10-30 13:22:00-05'::timestamptz -
    2882              :      *  test(>   '2005-10-29 13:22:00-04'::timestamptz);
    2883              :      *  ?column?
    2884              :      *  ----------------
    2885              :      *   1 day 01:00:00
    2886              :      *   (1 row)
    2887              :      *
    2888              :      *  so adding that to the first timestamp gets:
    2889              :      *
    2890              :      *   test=> SELECT
    2891              :      *   test-> ('2005-10-29 13:22:00-04'::timestamptz +
    2892              :      *   test(> ('2005-10-30 13:22:00-05'::timestamptz -
    2893              :      *   test(>  '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
    2894              :      *      timezone
    2895              :      *  --------------------
    2896              :      *  2005-10-30 14:22:00
    2897              :      *  (1 row)
    2898              :      *----------
    2899              :      */
    2900         3179 :     result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
    2901              :                                                    IntervalPGetDatum(result)));
    2902              : 
    2903         3179 :     PG_RETURN_INTERVAL_P(result);
    2904              : }
    2905              : 
    2906              : /*
    2907              :  *  interval_justify_interval()
    2908              :  *
    2909              :  *  Adjust interval so 'month', 'day', and 'time' portions are within
    2910              :  *  customary bounds.  Specifically:
    2911              :  *
    2912              :  *      0 <= abs(time) < 24 hours
    2913              :  *      0 <= abs(day)  < 30 days
    2914              :  *
    2915              :  *  Also, the sign bit on all three fields is made equal, so either
    2916              :  *  all three fields are negative or all are positive.
    2917              :  */
    2918              : Datum
    2919           33 : interval_justify_interval(PG_FUNCTION_ARGS)
    2920              : {
    2921           33 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    2922              :     Interval   *result;
    2923              :     TimeOffset  wholeday;
    2924              :     int32       wholemonth;
    2925              : 
    2926           33 :     result = palloc_object(Interval);
    2927           33 :     result->month = span->month;
    2928           33 :     result->day = span->day;
    2929           33 :     result->time = span->time;
    2930              : 
    2931              :     /* do nothing for infinite intervals */
    2932           33 :     if (INTERVAL_NOT_FINITE(result))
    2933            6 :         PG_RETURN_INTERVAL_P(result);
    2934              : 
    2935              :     /* pre-justify days if it might prevent overflow */
    2936           27 :     if ((result->day > 0 && result->time > 0) ||
    2937           24 :         (result->day < 0 && result->time < 0))
    2938              :     {
    2939            6 :         wholemonth = result->day / DAYS_PER_MONTH;
    2940            6 :         result->day -= wholemonth * DAYS_PER_MONTH;
    2941            6 :         if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
    2942            0 :             ereport(ERROR,
    2943              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2944              :                      errmsg("interval out of range")));
    2945              :     }
    2946              : 
    2947              :     /*
    2948              :      * Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8.  If
    2949              :      * we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so
    2950              :      * this addition can't overflow.  If we didn't pre-justify, then day and
    2951              :      * time are of different signs, so it still can't overflow.
    2952              :      */
    2953           27 :     TMODULO(result->time, wholeday, USECS_PER_DAY);
    2954           27 :     result->day += wholeday;
    2955              : 
    2956           27 :     wholemonth = result->day / DAYS_PER_MONTH;
    2957           27 :     result->day -= wholemonth * DAYS_PER_MONTH;
    2958           27 :     if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
    2959           12 :         ereport(ERROR,
    2960              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2961              :                  errmsg("interval out of range")));
    2962              : 
    2963           15 :     if (result->month > 0 &&
    2964            9 :         (result->day < 0 || (result->day == 0 && result->time < 0)))
    2965              :     {
    2966            3 :         result->day += DAYS_PER_MONTH;
    2967            3 :         result->month--;
    2968              :     }
    2969           12 :     else if (result->month < 0 &&
    2970            6 :              (result->day > 0 || (result->day == 0 && result->time > 0)))
    2971              :     {
    2972            0 :         result->day -= DAYS_PER_MONTH;
    2973            0 :         result->month++;
    2974              :     }
    2975              : 
    2976           15 :     if (result->day > 0 && result->time < 0)
    2977              :     {
    2978            3 :         result->time += USECS_PER_DAY;
    2979            3 :         result->day--;
    2980              :     }
    2981           12 :     else if (result->day < 0 && result->time > 0)
    2982              :     {
    2983            0 :         result->time -= USECS_PER_DAY;
    2984            0 :         result->day++;
    2985              :     }
    2986              : 
    2987           15 :     PG_RETURN_INTERVAL_P(result);
    2988              : }
    2989              : 
    2990              : /*
    2991              :  *  interval_justify_hours()
    2992              :  *
    2993              :  *  Adjust interval so 'time' contains less than a whole day, adding
    2994              :  *  the excess to 'day'.  This is useful for
    2995              :  *  situations (such as non-TZ) where '1 day' = '24 hours' is valid,
    2996              :  *  e.g. interval subtraction and division.
    2997              :  */
    2998              : Datum
    2999         4181 : interval_justify_hours(PG_FUNCTION_ARGS)
    3000              : {
    3001         4181 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3002              :     Interval   *result;
    3003              :     TimeOffset  wholeday;
    3004              : 
    3005         4181 :     result = palloc_object(Interval);
    3006         4181 :     result->month = span->month;
    3007         4181 :     result->day = span->day;
    3008         4181 :     result->time = span->time;
    3009              : 
    3010              :     /* do nothing for infinite intervals */
    3011         4181 :     if (INTERVAL_NOT_FINITE(result))
    3012            6 :         PG_RETURN_INTERVAL_P(result);
    3013              : 
    3014         4175 :     TMODULO(result->time, wholeday, USECS_PER_DAY);
    3015         4175 :     if (pg_add_s32_overflow(result->day, wholeday, &result->day))
    3016            3 :         ereport(ERROR,
    3017              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3018              :                  errmsg("interval out of range")));
    3019              : 
    3020         4172 :     if (result->day > 0 && result->time < 0)
    3021              :     {
    3022            0 :         result->time += USECS_PER_DAY;
    3023            0 :         result->day--;
    3024              :     }
    3025         4172 :     else if (result->day < 0 && result->time > 0)
    3026              :     {
    3027            0 :         result->time -= USECS_PER_DAY;
    3028            0 :         result->day++;
    3029              :     }
    3030              : 
    3031         4172 :     PG_RETURN_INTERVAL_P(result);
    3032              : }
    3033              : 
    3034              : /*
    3035              :  *  interval_justify_days()
    3036              :  *
    3037              :  *  Adjust interval so 'day' contains less than 30 days, adding
    3038              :  *  the excess to 'month'.
    3039              :  */
    3040              : Datum
    3041         1002 : interval_justify_days(PG_FUNCTION_ARGS)
    3042              : {
    3043         1002 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3044              :     Interval   *result;
    3045              :     int32       wholemonth;
    3046              : 
    3047         1002 :     result = palloc_object(Interval);
    3048         1002 :     result->month = span->month;
    3049         1002 :     result->day = span->day;
    3050         1002 :     result->time = span->time;
    3051              : 
    3052              :     /* do nothing for infinite intervals */
    3053         1002 :     if (INTERVAL_NOT_FINITE(result))
    3054            6 :         PG_RETURN_INTERVAL_P(result);
    3055              : 
    3056          996 :     wholemonth = result->day / DAYS_PER_MONTH;
    3057          996 :     result->day -= wholemonth * DAYS_PER_MONTH;
    3058          996 :     if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
    3059            3 :         ereport(ERROR,
    3060              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3061              :                  errmsg("interval out of range")));
    3062              : 
    3063          993 :     if (result->month > 0 && result->day < 0)
    3064              :     {
    3065            0 :         result->day += DAYS_PER_MONTH;
    3066            0 :         result->month--;
    3067              :     }
    3068          993 :     else if (result->month < 0 && result->day > 0)
    3069              :     {
    3070            0 :         result->day -= DAYS_PER_MONTH;
    3071            0 :         result->month++;
    3072              :     }
    3073              : 
    3074          993 :     PG_RETURN_INTERVAL_P(result);
    3075              : }
    3076              : 
    3077              : /* timestamp_pl_interval()
    3078              :  * Add an interval to a timestamp data type.
    3079              :  * Note that interval has provisions for qualitative year/month and day
    3080              :  *  units, so try to do the right thing with them.
    3081              :  * To add a month, increment the month, and use the same day of month.
    3082              :  * Then, if the next month has fewer days, set the day of month
    3083              :  *  to the last day of month.
    3084              :  * To add a day, increment the mday, and use the same time of day.
    3085              :  * Lastly, add in the "quantitative time".
    3086              :  */
    3087              : Datum
    3088         4980 : timestamp_pl_interval(PG_FUNCTION_ARGS)
    3089              : {
    3090         4980 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    3091         4980 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3092              :     Timestamp   result;
    3093              : 
    3094              :     /*
    3095              :      * Handle infinities.
    3096              :      *
    3097              :      * We treat anything that amounts to "infinity - infinity" as an error,
    3098              :      * since the timestamp type has nothing equivalent to NaN.
    3099              :      */
    3100         4980 :     if (INTERVAL_IS_NOBEGIN(span))
    3101              :     {
    3102          138 :         if (TIMESTAMP_IS_NOEND(timestamp))
    3103           12 :             ereport(ERROR,
    3104              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3105              :                      errmsg("timestamp out of range")));
    3106              :         else
    3107          126 :             TIMESTAMP_NOBEGIN(result);
    3108              :     }
    3109         4842 :     else if (INTERVAL_IS_NOEND(span))
    3110              :     {
    3111          102 :         if (TIMESTAMP_IS_NOBEGIN(timestamp))
    3112           12 :             ereport(ERROR,
    3113              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3114              :                      errmsg("timestamp out of range")));
    3115              :         else
    3116           90 :             TIMESTAMP_NOEND(result);
    3117              :     }
    3118         4740 :     else if (TIMESTAMP_NOT_FINITE(timestamp))
    3119           57 :         result = timestamp;
    3120              :     else
    3121              :     {
    3122         4683 :         if (span->month != 0)
    3123              :         {
    3124              :             struct pg_tm tt,
    3125         1314 :                        *tm = &tt;
    3126              :             fsec_t      fsec;
    3127              : 
    3128         1314 :             if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    3129            0 :                 ereport(ERROR,
    3130              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3131              :                          errmsg("timestamp out of range")));
    3132              : 
    3133         1314 :             if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
    3134            0 :                 ereport(ERROR,
    3135              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3136              :                          errmsg("timestamp out of range")));
    3137         1314 :             if (tm->tm_mon > MONTHS_PER_YEAR)
    3138              :             {
    3139          699 :                 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
    3140          699 :                 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
    3141              :             }
    3142          615 :             else if (tm->tm_mon < 1)
    3143              :             {
    3144          585 :                 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
    3145          585 :                 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
    3146              :             }
    3147              : 
    3148              :             /* adjust for end of month boundary problems... */
    3149         1314 :             if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    3150            6 :                 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
    3151              : 
    3152         1314 :             if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
    3153            0 :                 ereport(ERROR,
    3154              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3155              :                          errmsg("timestamp out of range")));
    3156              :         }
    3157              : 
    3158         4683 :         if (span->day != 0)
    3159              :         {
    3160              :             struct pg_tm tt,
    3161         1631 :                        *tm = &tt;
    3162              :             fsec_t      fsec;
    3163              :             int         julian;
    3164              : 
    3165         1631 :             if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    3166            0 :                 ereport(ERROR,
    3167              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3168              :                          errmsg("timestamp out of range")));
    3169              : 
    3170              :             /*
    3171              :              * Add days by converting to and from Julian.  We need an overflow
    3172              :              * check here since j2date expects a non-negative integer input.
    3173              :              */
    3174         1631 :             julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
    3175         1631 :             if (pg_add_s32_overflow(julian, span->day, &julian) ||
    3176         1631 :                 julian < 0)
    3177            3 :                 ereport(ERROR,
    3178              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3179              :                          errmsg("timestamp out of range")));
    3180         1628 :             j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    3181              : 
    3182         1628 :             if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
    3183            0 :                 ereport(ERROR,
    3184              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3185              :                          errmsg("timestamp out of range")));
    3186              :         }
    3187              : 
    3188         4680 :         if (pg_add_s64_overflow(timestamp, span->time, &timestamp))
    3189            3 :             ereport(ERROR,
    3190              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3191              :                      errmsg("timestamp out of range")));
    3192              : 
    3193         4677 :         if (!IS_VALID_TIMESTAMP(timestamp))
    3194            0 :             ereport(ERROR,
    3195              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3196              :                      errmsg("timestamp out of range")));
    3197              : 
    3198         4677 :         result = timestamp;
    3199              :     }
    3200              : 
    3201         4950 :     PG_RETURN_TIMESTAMP(result);
    3202              : }
    3203              : 
    3204              : Datum
    3205         1086 : timestamp_mi_interval(PG_FUNCTION_ARGS)
    3206              : {
    3207         1086 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    3208         1086 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3209              :     Interval    tspan;
    3210              : 
    3211         1086 :     interval_um_internal(span, &tspan);
    3212              : 
    3213         1086 :     return DirectFunctionCall2(timestamp_pl_interval,
    3214              :                                TimestampGetDatum(timestamp),
    3215              :                                PointerGetDatum(&tspan));
    3216              : }
    3217              : 
    3218              : 
    3219              : /* timestamptz_pl_interval_internal()
    3220              :  * Add an interval to a timestamptz, in the given (or session) timezone.
    3221              :  *
    3222              :  * Note that interval has provisions for qualitative year/month and day
    3223              :  *  units, so try to do the right thing with them.
    3224              :  * To add a month, increment the month, and use the same day of month.
    3225              :  * Then, if the next month has fewer days, set the day of month
    3226              :  *  to the last day of month.
    3227              :  * To add a day, increment the mday, and use the same time of day.
    3228              :  * Lastly, add in the "quantitative time".
    3229              :  */
    3230              : static TimestampTz
    3231        75996 : timestamptz_pl_interval_internal(TimestampTz timestamp,
    3232              :                                  Interval *span,
    3233              :                                  pg_tz *attimezone)
    3234              : {
    3235              :     TimestampTz result;
    3236              :     int         tz;
    3237              : 
    3238              :     /*
    3239              :      * Handle infinities.
    3240              :      *
    3241              :      * We treat anything that amounts to "infinity - infinity" as an error,
    3242              :      * since the timestamptz type has nothing equivalent to NaN.
    3243              :      */
    3244        75996 :     if (INTERVAL_IS_NOBEGIN(span))
    3245              :     {
    3246          216 :         if (TIMESTAMP_IS_NOEND(timestamp))
    3247            6 :             ereport(ERROR,
    3248              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3249              :                      errmsg("timestamp out of range")));
    3250              :         else
    3251          210 :             TIMESTAMP_NOBEGIN(result);
    3252              :     }
    3253        75780 :     else if (INTERVAL_IS_NOEND(span))
    3254              :     {
    3255          180 :         if (TIMESTAMP_IS_NOBEGIN(timestamp))
    3256            6 :             ereport(ERROR,
    3257              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3258              :                      errmsg("timestamp out of range")));
    3259              :         else
    3260          174 :             TIMESTAMP_NOEND(result);
    3261              :     }
    3262        75600 :     else if (TIMESTAMP_NOT_FINITE(timestamp))
    3263           60 :         result = timestamp;
    3264              :     else
    3265              :     {
    3266              :         /* Use session timezone if caller asks for default */
    3267        75540 :         if (attimezone == NULL)
    3268        44236 :             attimezone = session_timezone;
    3269              : 
    3270        75540 :         if (span->month != 0)
    3271              :         {
    3272              :             struct pg_tm tt,
    3273        27924 :                        *tm = &tt;
    3274              :             fsec_t      fsec;
    3275              : 
    3276        27924 :             if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
    3277            0 :                 ereport(ERROR,
    3278              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3279              :                          errmsg("timestamp out of range")));
    3280              : 
    3281        27924 :             if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
    3282            0 :                 ereport(ERROR,
    3283              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3284              :                          errmsg("timestamp out of range")));
    3285        27924 :             if (tm->tm_mon > MONTHS_PER_YEAR)
    3286              :             {
    3287        27033 :                 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
    3288        27033 :                 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
    3289              :             }
    3290          891 :             else if (tm->tm_mon < 1)
    3291              :             {
    3292          678 :                 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
    3293          678 :                 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
    3294              :             }
    3295              : 
    3296              :             /* adjust for end of month boundary problems... */
    3297        27924 :             if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    3298           27 :                 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
    3299              : 
    3300        27924 :             tz = DetermineTimeZoneOffset(tm, attimezone);
    3301              : 
    3302        27924 :             if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
    3303            0 :                 ereport(ERROR,
    3304              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3305              :                          errmsg("timestamp out of range")));
    3306              :         }
    3307              : 
    3308        75540 :         if (span->day != 0)
    3309              :         {
    3310              :             struct pg_tm tt,
    3311         1827 :                        *tm = &tt;
    3312              :             fsec_t      fsec;
    3313              :             int         julian;
    3314              : 
    3315         1827 :             if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
    3316            0 :                 ereport(ERROR,
    3317              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3318              :                          errmsg("timestamp out of range")));
    3319              : 
    3320              :             /*
    3321              :              * Add days by converting to and from Julian.  We need an overflow
    3322              :              * check here since j2date expects a non-negative integer input.
    3323              :              * In practice though, it will give correct answers for small
    3324              :              * negative Julian dates; we should allow -1 to avoid
    3325              :              * timezone-dependent failures, as discussed in timestamp.h.
    3326              :              */
    3327         1827 :             julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
    3328         1827 :             if (pg_add_s32_overflow(julian, span->day, &julian) ||
    3329         1827 :                 julian < -1)
    3330            3 :                 ereport(ERROR,
    3331              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3332              :                          errmsg("timestamp out of range")));
    3333         1824 :             j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    3334              : 
    3335         1824 :             tz = DetermineTimeZoneOffset(tm, attimezone);
    3336              : 
    3337         1824 :             if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
    3338            0 :                 ereport(ERROR,
    3339              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3340              :                          errmsg("timestamp out of range")));
    3341              :         }
    3342              : 
    3343        75537 :         if (pg_add_s64_overflow(timestamp, span->time, &timestamp))
    3344            3 :             ereport(ERROR,
    3345              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3346              :                      errmsg("timestamp out of range")));
    3347              : 
    3348        75534 :         if (!IS_VALID_TIMESTAMP(timestamp))
    3349            0 :             ereport(ERROR,
    3350              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3351              :                      errmsg("timestamp out of range")));
    3352              : 
    3353        75534 :         result = timestamp;
    3354              :     }
    3355              : 
    3356        75978 :     return result;
    3357              : }
    3358              : 
    3359              : /* timestamptz_mi_interval_internal()
    3360              :  * As above, but subtract the interval.
    3361              :  */
    3362              : static TimestampTz
    3363         1059 : timestamptz_mi_interval_internal(TimestampTz timestamp,
    3364              :                                  Interval *span,
    3365              :                                  pg_tz *attimezone)
    3366              : {
    3367              :     Interval    tspan;
    3368              : 
    3369         1059 :     interval_um_internal(span, &tspan);
    3370              : 
    3371         1059 :     return timestamptz_pl_interval_internal(timestamp, &tspan, attimezone);
    3372              : }
    3373              : 
    3374              : /* timestamptz_pl_interval()
    3375              :  * Add an interval to a timestamptz, in the session timezone.
    3376              :  */
    3377              : Datum
    3378        43429 : timestamptz_pl_interval(PG_FUNCTION_ARGS)
    3379              : {
    3380        43429 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    3381        43429 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3382              : 
    3383        43429 :     PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, NULL));
    3384              : }
    3385              : 
    3386              : Datum
    3387          816 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
    3388              : {
    3389          816 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    3390          816 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3391              : 
    3392          816 :     PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, NULL));
    3393              : }
    3394              : 
    3395              : /* timestamptz_pl_interval_at_zone()
    3396              :  * Add an interval to a timestamptz, in the specified timezone.
    3397              :  */
    3398              : Datum
    3399            3 : timestamptz_pl_interval_at_zone(PG_FUNCTION_ARGS)
    3400              : {
    3401            3 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    3402            3 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3403            3 :     text       *zone = PG_GETARG_TEXT_PP(2);
    3404            3 :     pg_tz      *attimezone = lookup_timezone(zone);
    3405              : 
    3406            3 :     PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, attimezone));
    3407              : }
    3408              : 
    3409              : Datum
    3410            3 : timestamptz_mi_interval_at_zone(PG_FUNCTION_ARGS)
    3411              : {
    3412            3 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    3413            3 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3414            3 :     text       *zone = PG_GETARG_TEXT_PP(2);
    3415            3 :     pg_tz      *attimezone = lookup_timezone(zone);
    3416              : 
    3417            3 :     PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, attimezone));
    3418              : }
    3419              : 
    3420              : /* interval_um_internal()
    3421              :  * Negate an interval.
    3422              :  */
    3423              : static void
    3424         4020 : interval_um_internal(const Interval *interval, Interval *result)
    3425              : {
    3426         4020 :     if (INTERVAL_IS_NOBEGIN(interval))
    3427          135 :         INTERVAL_NOEND(result);
    3428         3885 :     else if (INTERVAL_IS_NOEND(interval))
    3429          339 :         INTERVAL_NOBEGIN(result);
    3430              :     else
    3431              :     {
    3432              :         /* Negate each field, guarding against overflow */
    3433         7089 :         if (pg_sub_s64_overflow(INT64CONST(0), interval->time, &result->time) ||
    3434         7083 :             pg_sub_s32_overflow(0, interval->day, &result->day) ||
    3435         3540 :             pg_sub_s32_overflow(0, interval->month, &result->month) ||
    3436         3537 :             INTERVAL_NOT_FINITE(result))
    3437           15 :             ereport(ERROR,
    3438              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3439              :                      errmsg("interval out of range")));
    3440              :     }
    3441         4005 : }
    3442              : 
    3443              : Datum
    3444         1857 : interval_um(PG_FUNCTION_ARGS)
    3445              : {
    3446         1857 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    3447              :     Interval   *result;
    3448              : 
    3449         1857 :     result = palloc_object(Interval);
    3450         1857 :     interval_um_internal(interval, result);
    3451              : 
    3452         1842 :     PG_RETURN_INTERVAL_P(result);
    3453              : }
    3454              : 
    3455              : 
    3456              : Datum
    3457            0 : interval_smaller(PG_FUNCTION_ARGS)
    3458              : {
    3459            0 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    3460            0 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    3461              :     Interval   *result;
    3462              : 
    3463              :     /* use interval_cmp_internal to be sure this agrees with comparisons */
    3464            0 :     if (interval_cmp_internal(interval1, interval2) < 0)
    3465            0 :         result = interval1;
    3466              :     else
    3467            0 :         result = interval2;
    3468            0 :     PG_RETURN_INTERVAL_P(result);
    3469              : }
    3470              : 
    3471              : Datum
    3472            0 : interval_larger(PG_FUNCTION_ARGS)
    3473              : {
    3474            0 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    3475            0 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    3476              :     Interval   *result;
    3477              : 
    3478            0 :     if (interval_cmp_internal(interval1, interval2) > 0)
    3479            0 :         result = interval1;
    3480              :     else
    3481            0 :         result = interval2;
    3482            0 :     PG_RETURN_INTERVAL_P(result);
    3483              : }
    3484              : 
    3485              : static void
    3486          264 : finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result)
    3487              : {
    3488              :     Assert(!INTERVAL_NOT_FINITE(span1));
    3489              :     Assert(!INTERVAL_NOT_FINITE(span2));
    3490              : 
    3491          528 :     if (pg_add_s32_overflow(span1->month, span2->month, &result->month) ||
    3492          528 :         pg_add_s32_overflow(span1->day, span2->day, &result->day) ||
    3493          264 :         pg_add_s64_overflow(span1->time, span2->time, &result->time) ||
    3494          264 :         INTERVAL_NOT_FINITE(result))
    3495            6 :         ereport(ERROR,
    3496              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3497              :                  errmsg("interval out of range")));
    3498          258 : }
    3499              : 
    3500              : Datum
    3501          279 : interval_pl(PG_FUNCTION_ARGS)
    3502              : {
    3503          279 :     Interval   *span1 = PG_GETARG_INTERVAL_P(0);
    3504          279 :     Interval   *span2 = PG_GETARG_INTERVAL_P(1);
    3505              :     Interval   *result;
    3506              : 
    3507          279 :     result = palloc_object(Interval);
    3508              : 
    3509              :     /*
    3510              :      * Handle infinities.
    3511              :      *
    3512              :      * We treat anything that amounts to "infinity - infinity" as an error,
    3513              :      * since the interval type has nothing equivalent to NaN.
    3514              :      */
    3515          279 :     if (INTERVAL_IS_NOBEGIN(span1))
    3516              :     {
    3517           27 :         if (INTERVAL_IS_NOEND(span2))
    3518            3 :             ereport(ERROR,
    3519              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3520              :                      errmsg("interval out of range")));
    3521              :         else
    3522           24 :             INTERVAL_NOBEGIN(result);
    3523              :     }
    3524          252 :     else if (INTERVAL_IS_NOEND(span1))
    3525              :     {
    3526           21 :         if (INTERVAL_IS_NOBEGIN(span2))
    3527            3 :             ereport(ERROR,
    3528              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3529              :                      errmsg("interval out of range")));
    3530              :         else
    3531           18 :             INTERVAL_NOEND(result);
    3532              :     }
    3533          231 :     else if (INTERVAL_NOT_FINITE(span2))
    3534           69 :         memcpy(result, span2, sizeof(Interval));
    3535              :     else
    3536          162 :         finite_interval_pl(span1, span2, result);
    3537              : 
    3538          267 :     PG_RETURN_INTERVAL_P(result);
    3539              : }
    3540              : 
    3541              : static void
    3542          774 : finite_interval_mi(const Interval *span1, const Interval *span2, Interval *result)
    3543              : {
    3544              :     Assert(!INTERVAL_NOT_FINITE(span1));
    3545              :     Assert(!INTERVAL_NOT_FINITE(span2));
    3546              : 
    3547         1548 :     if (pg_sub_s32_overflow(span1->month, span2->month, &result->month) ||
    3548         1548 :         pg_sub_s32_overflow(span1->day, span2->day, &result->day) ||
    3549          774 :         pg_sub_s64_overflow(span1->time, span2->time, &result->time) ||
    3550          774 :         INTERVAL_NOT_FINITE(result))
    3551            6 :         ereport(ERROR,
    3552              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3553              :                  errmsg("interval out of range")));
    3554          768 : }
    3555              : 
    3556              : Datum
    3557          897 : interval_mi(PG_FUNCTION_ARGS)
    3558              : {
    3559          897 :     Interval   *span1 = PG_GETARG_INTERVAL_P(0);
    3560          897 :     Interval   *span2 = PG_GETARG_INTERVAL_P(1);
    3561              :     Interval   *result;
    3562              : 
    3563          897 :     result = palloc_object(Interval);
    3564              : 
    3565              :     /*
    3566              :      * Handle infinities.
    3567              :      *
    3568              :      * We treat anything that amounts to "infinity - infinity" as an error,
    3569              :      * since the interval type has nothing equivalent to NaN.
    3570              :      */
    3571          897 :     if (INTERVAL_IS_NOBEGIN(span1))
    3572              :     {
    3573           27 :         if (INTERVAL_IS_NOBEGIN(span2))
    3574            3 :             ereport(ERROR,
    3575              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3576              :                      errmsg("interval out of range")));
    3577              :         else
    3578           24 :             INTERVAL_NOBEGIN(result);
    3579              :     }
    3580          870 :     else if (INTERVAL_IS_NOEND(span1))
    3581              :     {
    3582           24 :         if (INTERVAL_IS_NOEND(span2))
    3583            3 :             ereport(ERROR,
    3584              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3585              :                      errmsg("interval out of range")));
    3586              :         else
    3587           21 :             INTERVAL_NOEND(result);
    3588              :     }
    3589          846 :     else if (INTERVAL_IS_NOBEGIN(span2))
    3590            3 :         INTERVAL_NOEND(result);
    3591          843 :     else if (INTERVAL_IS_NOEND(span2))
    3592           93 :         INTERVAL_NOBEGIN(result);
    3593              :     else
    3594          750 :         finite_interval_mi(span1, span2, result);
    3595              : 
    3596          885 :     PG_RETURN_INTERVAL_P(result);
    3597              : }
    3598              : 
    3599              : /*
    3600              :  *  There is no interval_abs():  it is unclear what value to return:
    3601              :  *    http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
    3602              :  *    http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
    3603              :  */
    3604              : 
    3605              : Datum
    3606         5826 : interval_mul(PG_FUNCTION_ARGS)
    3607              : {
    3608         5826 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3609         5826 :     float8      factor = PG_GETARG_FLOAT8(1);
    3610              :     double      month_remainder_days,
    3611              :                 sec_remainder,
    3612              :                 result_double;
    3613         5826 :     int32       orig_month = span->month,
    3614         5826 :                 orig_day = span->day;
    3615              :     Interval   *result;
    3616              : 
    3617         5826 :     result = palloc_object(Interval);
    3618              : 
    3619              :     /*
    3620              :      * Handle NaN and infinities.
    3621              :      *
    3622              :      * We treat "0 * infinity" and "infinity * 0" as errors, since the
    3623              :      * interval type has nothing equivalent to NaN.
    3624              :      */
    3625         5826 :     if (isnan(factor))
    3626            6 :         goto out_of_range;
    3627              : 
    3628         5820 :     if (INTERVAL_NOT_FINITE(span))
    3629              :     {
    3630           30 :         if (factor == 0.0)
    3631            6 :             goto out_of_range;
    3632              : 
    3633           24 :         if (factor < 0.0)
    3634           12 :             interval_um_internal(span, result);
    3635              :         else
    3636           12 :             memcpy(result, span, sizeof(Interval));
    3637              : 
    3638           24 :         PG_RETURN_INTERVAL_P(result);
    3639              :     }
    3640         5790 :     if (isinf(factor))
    3641              :     {
    3642           12 :         int         isign = interval_sign(span);
    3643              : 
    3644           12 :         if (isign == 0)
    3645            6 :             goto out_of_range;
    3646              : 
    3647            6 :         if (factor * isign < 0)
    3648            3 :             INTERVAL_NOBEGIN(result);
    3649              :         else
    3650            3 :             INTERVAL_NOEND(result);
    3651              : 
    3652            6 :         PG_RETURN_INTERVAL_P(result);
    3653              :     }
    3654              : 
    3655         5778 :     result_double = span->month * factor;
    3656         5778 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
    3657            3 :         goto out_of_range;
    3658         5775 :     result->month = (int32) result_double;
    3659              : 
    3660         5775 :     result_double = span->day * factor;
    3661         5775 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
    3662            3 :         goto out_of_range;
    3663         5772 :     result->day = (int32) result_double;
    3664              : 
    3665              :     /*
    3666              :      * The above correctly handles the whole-number part of the month and day
    3667              :      * products, but we have to do something with any fractional part
    3668              :      * resulting when the factor is non-integral.  We cascade the fractions
    3669              :      * down to lower units using the conversion factors DAYS_PER_MONTH and
    3670              :      * SECS_PER_DAY.  Note we do NOT cascade up, since we are not forced to do
    3671              :      * so by the representation.  The user can choose to cascade up later,
    3672              :      * using justify_hours and/or justify_days.
    3673              :      */
    3674              : 
    3675              :     /*
    3676              :      * Fractional months full days into days.
    3677              :      *
    3678              :      * Floating point calculation are inherently imprecise, so these
    3679              :      * calculations are crafted to produce the most reliable result possible.
    3680              :      * TSROUND() is needed to more accurately produce whole numbers where
    3681              :      * appropriate.
    3682              :      */
    3683         5772 :     month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
    3684         5772 :     month_remainder_days = TSROUND(month_remainder_days);
    3685         5772 :     sec_remainder = (orig_day * factor - result->day +
    3686         5772 :                      month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
    3687         5772 :     sec_remainder = TSROUND(sec_remainder);
    3688              : 
    3689              :     /*
    3690              :      * Might have 24:00:00 hours due to rounding, or >24 hours because of time
    3691              :      * cascade from months and days.  It might still be >24 if the combination
    3692              :      * of cascade and the seconds factor operation itself.
    3693              :      */
    3694         5772 :     if (fabs(sec_remainder) >= SECS_PER_DAY)
    3695              :     {
    3696            0 :         if (pg_add_s32_overflow(result->day,
    3697            0 :                                 (int) (sec_remainder / SECS_PER_DAY),
    3698              :                                 &result->day))
    3699            0 :             goto out_of_range;
    3700            0 :         sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
    3701              :     }
    3702              : 
    3703              :     /* cascade units down */
    3704         5772 :     if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
    3705              :                             &result->day))
    3706            3 :         goto out_of_range;
    3707         5769 :     result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
    3708         5769 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
    3709            3 :         goto out_of_range;
    3710         5766 :     result->time = (int64) result_double;
    3711              : 
    3712         5766 :     if (INTERVAL_NOT_FINITE(result))
    3713            3 :         goto out_of_range;
    3714              : 
    3715         5763 :     PG_RETURN_INTERVAL_P(result);
    3716              : 
    3717           33 : out_of_range:
    3718           33 :     ereport(ERROR,
    3719              :             errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3720              :             errmsg("interval out of range"));
    3721              : 
    3722              :     PG_RETURN_NULL();           /* keep compiler quiet */
    3723              : }
    3724              : 
    3725              : Datum
    3726         5715 : mul_d_interval(PG_FUNCTION_ARGS)
    3727              : {
    3728              :     /* Args are float8 and Interval *, but leave them as generic Datum */
    3729         5715 :     Datum       factor = PG_GETARG_DATUM(0);
    3730         5715 :     Datum       span = PG_GETARG_DATUM(1);
    3731              : 
    3732         5715 :     return DirectFunctionCall2(interval_mul, span, factor);
    3733              : }
    3734              : 
    3735              : Datum
    3736          111 : interval_div(PG_FUNCTION_ARGS)
    3737              : {
    3738          111 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3739          111 :     float8      factor = PG_GETARG_FLOAT8(1);
    3740              :     double      month_remainder_days,
    3741              :                 sec_remainder,
    3742              :                 result_double;
    3743          111 :     int32       orig_month = span->month,
    3744          111 :                 orig_day = span->day;
    3745              :     Interval   *result;
    3746              : 
    3747          111 :     result = palloc_object(Interval);
    3748              : 
    3749          111 :     if (factor == 0.0)
    3750            0 :         ereport(ERROR,
    3751              :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
    3752              :                  errmsg("division by zero")));
    3753              : 
    3754              :     /*
    3755              :      * Handle NaN and infinities.
    3756              :      *
    3757              :      * We treat "infinity / infinity" as an error, since the interval type has
    3758              :      * nothing equivalent to NaN.  Otherwise, dividing by infinity is handled
    3759              :      * by the regular division code, causing all fields to be set to zero.
    3760              :      */
    3761          111 :     if (isnan(factor))
    3762            6 :         goto out_of_range;
    3763              : 
    3764          105 :     if (INTERVAL_NOT_FINITE(span))
    3765              :     {
    3766           24 :         if (isinf(factor))
    3767           12 :             goto out_of_range;
    3768              : 
    3769           12 :         if (factor < 0.0)
    3770            6 :             interval_um_internal(span, result);
    3771              :         else
    3772            6 :             memcpy(result, span, sizeof(Interval));
    3773              : 
    3774           12 :         PG_RETURN_INTERVAL_P(result);
    3775              :     }
    3776              : 
    3777           81 :     result_double = span->month / factor;
    3778           81 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
    3779            3 :         goto out_of_range;
    3780           78 :     result->month = (int32) result_double;
    3781              : 
    3782           78 :     result_double = span->day / factor;
    3783           78 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
    3784            3 :         goto out_of_range;
    3785           75 :     result->day = (int32) result_double;
    3786              : 
    3787              :     /*
    3788              :      * Fractional months full days into days.  See comment in interval_mul().
    3789              :      */
    3790           75 :     month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
    3791           75 :     month_remainder_days = TSROUND(month_remainder_days);
    3792           75 :     sec_remainder = (orig_day / factor - result->day +
    3793           75 :                      month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
    3794           75 :     sec_remainder = TSROUND(sec_remainder);
    3795           75 :     if (fabs(sec_remainder) >= SECS_PER_DAY)
    3796              :     {
    3797            3 :         if (pg_add_s32_overflow(result->day,
    3798            3 :                                 (int) (sec_remainder / SECS_PER_DAY),
    3799              :                                 &result->day))
    3800            0 :             goto out_of_range;
    3801            3 :         sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
    3802              :     }
    3803              : 
    3804              :     /* cascade units down */
    3805           75 :     if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
    3806              :                             &result->day))
    3807            0 :         goto out_of_range;
    3808           75 :     result_double = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
    3809           75 :     if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
    3810            3 :         goto out_of_range;
    3811           72 :     result->time = (int64) result_double;
    3812              : 
    3813           72 :     if (INTERVAL_NOT_FINITE(result))
    3814            3 :         goto out_of_range;
    3815              : 
    3816           69 :     PG_RETURN_INTERVAL_P(result);
    3817              : 
    3818           30 : out_of_range:
    3819           30 :     ereport(ERROR,
    3820              :             errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3821              :             errmsg("interval out of range"));
    3822              : 
    3823              :     PG_RETURN_NULL();           /* keep compiler quiet */
    3824              : }
    3825              : 
    3826              : 
    3827              : /*
    3828              :  * in_range support functions for timestamps and intervals.
    3829              :  *
    3830              :  * Per SQL spec, we support these with interval as the offset type.
    3831              :  * The spec's restriction that the offset not be negative is a bit hard to
    3832              :  * decipher for intervals, but we choose to interpret it the same as our
    3833              :  * interval comparison operators would.
    3834              :  */
    3835              : 
    3836              : Datum
    3837          567 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
    3838              : {
    3839          567 :     TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
    3840          567 :     TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
    3841          567 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3842          567 :     bool        sub = PG_GETARG_BOOL(3);
    3843          567 :     bool        less = PG_GETARG_BOOL(4);
    3844              :     TimestampTz sum;
    3845              : 
    3846          567 :     if (interval_sign(offset) < 0)
    3847            6 :         ereport(ERROR,
    3848              :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3849              :                  errmsg("invalid preceding or following size in window function")));
    3850              : 
    3851              :     /*
    3852              :      * Deal with cases where both base and offset are infinite, and computing
    3853              :      * base +/- offset would cause an error.  As for float and numeric types,
    3854              :      * we assume that all values infinitely precede +infinity and infinitely
    3855              :      * follow -infinity.  See in_range_float8_float8() for reasoning.
    3856              :      */
    3857          561 :     if (INTERVAL_IS_NOEND(offset) &&
    3858              :         (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
    3859          114 :         PG_RETURN_BOOL(true);
    3860              : 
    3861              :     /* We don't currently bother to avoid overflow hazards here */
    3862          447 :     if (sub)
    3863          240 :         sum = timestamptz_mi_interval_internal(base, offset, NULL);
    3864              :     else
    3865          207 :         sum = timestamptz_pl_interval_internal(base, offset, NULL);
    3866              : 
    3867          447 :     if (less)
    3868          177 :         PG_RETURN_BOOL(val <= sum);
    3869              :     else
    3870          270 :         PG_RETURN_BOOL(val >= sum);
    3871              : }
    3872              : 
    3873              : Datum
    3874         1233 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
    3875              : {
    3876         1233 :     Timestamp   val = PG_GETARG_TIMESTAMP(0);
    3877         1233 :     Timestamp   base = PG_GETARG_TIMESTAMP(1);
    3878         1233 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3879         1233 :     bool        sub = PG_GETARG_BOOL(3);
    3880         1233 :     bool        less = PG_GETARG_BOOL(4);
    3881              :     Timestamp   sum;
    3882              : 
    3883         1233 :     if (interval_sign(offset) < 0)
    3884            9 :         ereport(ERROR,
    3885              :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3886              :                  errmsg("invalid preceding or following size in window function")));
    3887              : 
    3888              :     /*
    3889              :      * Deal with cases where both base and offset are infinite, and computing
    3890              :      * base +/- offset would cause an error.  As for float and numeric types,
    3891              :      * we assume that all values infinitely precede +infinity and infinitely
    3892              :      * follow -infinity.  See in_range_float8_float8() for reasoning.
    3893              :      */
    3894         1224 :     if (INTERVAL_IS_NOEND(offset) &&
    3895              :         (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
    3896          114 :         PG_RETURN_BOOL(true);
    3897              : 
    3898              :     /* We don't currently bother to avoid overflow hazards here */
    3899         1110 :     if (sub)
    3900          516 :         sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
    3901              :                                                     TimestampGetDatum(base),
    3902              :                                                     IntervalPGetDatum(offset)));
    3903              :     else
    3904          594 :         sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
    3905              :                                                     TimestampGetDatum(base),
    3906              :                                                     IntervalPGetDatum(offset)));
    3907              : 
    3908         1110 :     if (less)
    3909          603 :         PG_RETURN_BOOL(val <= sum);
    3910              :     else
    3911          507 :         PG_RETURN_BOOL(val >= sum);
    3912              : }
    3913              : 
    3914              : Datum
    3915          564 : in_range_interval_interval(PG_FUNCTION_ARGS)
    3916              : {
    3917          564 :     Interval   *val = PG_GETARG_INTERVAL_P(0);
    3918          564 :     Interval   *base = PG_GETARG_INTERVAL_P(1);
    3919          564 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3920          564 :     bool        sub = PG_GETARG_BOOL(3);
    3921          564 :     bool        less = PG_GETARG_BOOL(4);
    3922              :     Interval   *sum;
    3923              : 
    3924          564 :     if (interval_sign(offset) < 0)
    3925            6 :         ereport(ERROR,
    3926              :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3927              :                  errmsg("invalid preceding or following size in window function")));
    3928              : 
    3929              :     /*
    3930              :      * Deal with cases where both base and offset are infinite, and computing
    3931              :      * base +/- offset would cause an error.  As for float and numeric types,
    3932              :      * we assume that all values infinitely precede +infinity and infinitely
    3933              :      * follow -infinity.  See in_range_float8_float8() for reasoning.
    3934              :      */
    3935          840 :     if (INTERVAL_IS_NOEND(offset) &&
    3936          282 :         (sub ? INTERVAL_IS_NOEND(base) : INTERVAL_IS_NOBEGIN(base)))
    3937          114 :         PG_RETURN_BOOL(true);
    3938              : 
    3939              :     /* We don't currently bother to avoid overflow hazards here */
    3940          444 :     if (sub)
    3941          240 :         sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
    3942              :                                                     IntervalPGetDatum(base),
    3943              :                                                     IntervalPGetDatum(offset)));
    3944              :     else
    3945          204 :         sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
    3946              :                                                     IntervalPGetDatum(base),
    3947              :                                                     IntervalPGetDatum(offset)));
    3948              : 
    3949          444 :     if (less)
    3950          174 :         PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
    3951              :     else
    3952          270 :         PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
    3953              : }
    3954              : 
    3955              : 
    3956              : /*
    3957              :  * Prepare state data for an interval aggregate function, that needs to compute
    3958              :  * sum and count, in the aggregate's memory context.
    3959              :  *
    3960              :  * The function is used when the state data needs to be allocated in aggregate's
    3961              :  * context. When the state data needs to be allocated in the current memory
    3962              :  * context, we use palloc0 directly e.g. interval_avg_deserialize().
    3963              :  */
    3964              : static IntervalAggState *
    3965           27 : makeIntervalAggState(FunctionCallInfo fcinfo)
    3966              : {
    3967              :     IntervalAggState *state;
    3968              :     MemoryContext agg_context;
    3969              :     MemoryContext old_context;
    3970              : 
    3971           27 :     if (!AggCheckCallContext(fcinfo, &agg_context))
    3972            0 :         elog(ERROR, "aggregate function called in non-aggregate context");
    3973              : 
    3974           27 :     old_context = MemoryContextSwitchTo(agg_context);
    3975              : 
    3976           27 :     state = palloc0_object(IntervalAggState);
    3977              : 
    3978           27 :     MemoryContextSwitchTo(old_context);
    3979              : 
    3980           27 :     return state;
    3981              : }
    3982              : 
    3983              : /*
    3984              :  * Accumulate a new input value for interval aggregate functions.
    3985              :  */
    3986              : static void
    3987          162 : do_interval_accum(IntervalAggState *state, Interval *newval)
    3988              : {
    3989              :     /* Infinite inputs are counted separately, and do not affect "N" */
    3990          162 :     if (INTERVAL_IS_NOBEGIN(newval))
    3991              :     {
    3992           30 :         state->nInfcount++;
    3993           30 :         return;
    3994              :     }
    3995              : 
    3996          132 :     if (INTERVAL_IS_NOEND(newval))
    3997              :     {
    3998           30 :         state->pInfcount++;
    3999           30 :         return;
    4000              :     }
    4001              : 
    4002          102 :     finite_interval_pl(&state->sumX, newval, &state->sumX);
    4003          102 :     state->N++;
    4004              : }
    4005              : 
    4006              : /*
    4007              :  * Remove the given interval value from the aggregated state.
    4008              :  */
    4009              : static void
    4010          102 : do_interval_discard(IntervalAggState *state, Interval *newval)
    4011              : {
    4012              :     /* Infinite inputs are counted separately, and do not affect "N" */
    4013          102 :     if (INTERVAL_IS_NOBEGIN(newval))
    4014              :     {
    4015           12 :         state->nInfcount--;
    4016           12 :         return;
    4017              :     }
    4018              : 
    4019           90 :     if (INTERVAL_IS_NOEND(newval))
    4020              :     {
    4021           24 :         state->pInfcount--;
    4022           24 :         return;
    4023              :     }
    4024              : 
    4025              :     /* Handle the to-be-discarded finite value. */
    4026           66 :     state->N--;
    4027           66 :     if (state->N > 0)
    4028           24 :         finite_interval_mi(&state->sumX, newval, &state->sumX);
    4029              :     else
    4030              :     {
    4031              :         /* All values discarded, reset the state */
    4032              :         Assert(state->N == 0);
    4033           42 :         memset(&state->sumX, 0, sizeof(state->sumX));
    4034              :     }
    4035              : }
    4036              : 
    4037              : /*
    4038              :  * Transition function for sum() and avg() interval aggregates.
    4039              :  */
    4040              : Datum
    4041          204 : interval_avg_accum(PG_FUNCTION_ARGS)
    4042              : {
    4043              :     IntervalAggState *state;
    4044              : 
    4045          204 :     state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
    4046              : 
    4047              :     /* Create the state data on the first call */
    4048          204 :     if (state == NULL)
    4049           27 :         state = makeIntervalAggState(fcinfo);
    4050              : 
    4051          204 :     if (!PG_ARGISNULL(1))
    4052          162 :         do_interval_accum(state, PG_GETARG_INTERVAL_P(1));
    4053              : 
    4054          204 :     PG_RETURN_POINTER(state);
    4055              : }
    4056              : 
    4057              : /*
    4058              :  * Combine function for sum() and avg() interval aggregates.
    4059              :  *
    4060              :  * Combine the given internal aggregate states and place the combination in
    4061              :  * the first argument.
    4062              :  */
    4063              : Datum
    4064            0 : interval_avg_combine(PG_FUNCTION_ARGS)
    4065              : {
    4066              :     IntervalAggState *state1;
    4067              :     IntervalAggState *state2;
    4068              : 
    4069            0 :     state1 = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
    4070            0 :     state2 = PG_ARGISNULL(1) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(1);
    4071              : 
    4072            0 :     if (state2 == NULL)
    4073            0 :         PG_RETURN_POINTER(state1);
    4074              : 
    4075            0 :     if (state1 == NULL)
    4076              :     {
    4077              :         /* manually copy all fields from state2 to state1 */
    4078            0 :         state1 = makeIntervalAggState(fcinfo);
    4079              : 
    4080            0 :         state1->N = state2->N;
    4081            0 :         state1->pInfcount = state2->pInfcount;
    4082            0 :         state1->nInfcount = state2->nInfcount;
    4083              : 
    4084            0 :         state1->sumX.day = state2->sumX.day;
    4085            0 :         state1->sumX.month = state2->sumX.month;
    4086            0 :         state1->sumX.time = state2->sumX.time;
    4087              : 
    4088            0 :         PG_RETURN_POINTER(state1);
    4089              :     }
    4090              : 
    4091            0 :     state1->N += state2->N;
    4092            0 :     state1->pInfcount += state2->pInfcount;
    4093            0 :     state1->nInfcount += state2->nInfcount;
    4094              : 
    4095              :     /* Accumulate finite interval values, if any. */
    4096            0 :     if (state2->N > 0)
    4097            0 :         finite_interval_pl(&state1->sumX, &state2->sumX, &state1->sumX);
    4098              : 
    4099            0 :     PG_RETURN_POINTER(state1);
    4100              : }
    4101              : 
    4102              : /*
    4103              :  * interval_avg_serialize
    4104              :  *      Serialize IntervalAggState for interval aggregates.
    4105              :  */
    4106              : Datum
    4107            0 : interval_avg_serialize(PG_FUNCTION_ARGS)
    4108              : {
    4109              :     IntervalAggState *state;
    4110              :     StringInfoData buf;
    4111              :     bytea      *result;
    4112              : 
    4113              :     /* Ensure we disallow calling when not in aggregate context */
    4114            0 :     if (!AggCheckCallContext(fcinfo, NULL))
    4115            0 :         elog(ERROR, "aggregate function called in non-aggregate context");
    4116              : 
    4117            0 :     state = (IntervalAggState *) PG_GETARG_POINTER(0);
    4118              : 
    4119            0 :     pq_begintypsend(&buf);
    4120              : 
    4121              :     /* N */
    4122            0 :     pq_sendint64(&buf, state->N);
    4123              : 
    4124              :     /* sumX */
    4125            0 :     pq_sendint64(&buf, state->sumX.time);
    4126            0 :     pq_sendint32(&buf, state->sumX.day);
    4127            0 :     pq_sendint32(&buf, state->sumX.month);
    4128              : 
    4129              :     /* pInfcount */
    4130            0 :     pq_sendint64(&buf, state->pInfcount);
    4131              : 
    4132              :     /* nInfcount */
    4133            0 :     pq_sendint64(&buf, state->nInfcount);
    4134              : 
    4135            0 :     result = pq_endtypsend(&buf);
    4136              : 
    4137            0 :     PG_RETURN_BYTEA_P(result);
    4138              : }
    4139              : 
    4140              : /*
    4141              :  * interval_avg_deserialize
    4142              :  *      Deserialize bytea into IntervalAggState for interval aggregates.
    4143              :  */
    4144              : Datum
    4145            0 : interval_avg_deserialize(PG_FUNCTION_ARGS)
    4146              : {
    4147              :     bytea      *sstate;
    4148              :     IntervalAggState *result;
    4149              :     StringInfoData buf;
    4150              : 
    4151            0 :     if (!AggCheckCallContext(fcinfo, NULL))
    4152            0 :         elog(ERROR, "aggregate function called in non-aggregate context");
    4153              : 
    4154            0 :     sstate = PG_GETARG_BYTEA_PP(0);
    4155              : 
    4156              :     /*
    4157              :      * Initialize a StringInfo so that we can "receive" it using the standard
    4158              :      * recv-function infrastructure.
    4159              :      */
    4160            0 :     initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
    4161            0 :                            VARSIZE_ANY_EXHDR(sstate));
    4162              : 
    4163            0 :     result = palloc0_object(IntervalAggState);
    4164              : 
    4165              :     /* N */
    4166            0 :     result->N = pq_getmsgint64(&buf);
    4167              : 
    4168              :     /* sumX */
    4169            0 :     result->sumX.time = pq_getmsgint64(&buf);
    4170            0 :     result->sumX.day = pq_getmsgint(&buf, 4);
    4171            0 :     result->sumX.month = pq_getmsgint(&buf, 4);
    4172              : 
    4173              :     /* pInfcount */
    4174            0 :     result->pInfcount = pq_getmsgint64(&buf);
    4175              : 
    4176              :     /* nInfcount */
    4177            0 :     result->nInfcount = pq_getmsgint64(&buf);
    4178              : 
    4179            0 :     pq_getmsgend(&buf);
    4180              : 
    4181            0 :     PG_RETURN_POINTER(result);
    4182              : }
    4183              : 
    4184              : /*
    4185              :  * Inverse transition function for sum() and avg() interval aggregates.
    4186              :  */
    4187              : Datum
    4188          132 : interval_avg_accum_inv(PG_FUNCTION_ARGS)
    4189              : {
    4190              :     IntervalAggState *state;
    4191              : 
    4192          132 :     state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
    4193              : 
    4194              :     /* Should not get here with no state */
    4195          132 :     if (state == NULL)
    4196            0 :         elog(ERROR, "interval_avg_accum_inv called with NULL state");
    4197              : 
    4198          132 :     if (!PG_ARGISNULL(1))
    4199          102 :         do_interval_discard(state, PG_GETARG_INTERVAL_P(1));
    4200              : 
    4201          132 :     PG_RETURN_POINTER(state);
    4202              : }
    4203              : 
    4204              : /* avg(interval) aggregate final function */
    4205              : Datum
    4206           84 : interval_avg(PG_FUNCTION_ARGS)
    4207              : {
    4208              :     IntervalAggState *state;
    4209              : 
    4210           84 :     state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
    4211              : 
    4212              :     /* If there were no non-null inputs, return NULL */
    4213           84 :     if (state == NULL || IA_TOTAL_COUNT(state) == 0)
    4214            9 :         PG_RETURN_NULL();
    4215              : 
    4216              :     /*
    4217              :      * Aggregating infinities that all have the same sign produces infinity
    4218              :      * with that sign.  Aggregating infinities with different signs results in
    4219              :      * an error.
    4220              :      */
    4221           75 :     if (state->pInfcount > 0 || state->nInfcount > 0)
    4222              :     {
    4223              :         Interval   *result;
    4224              : 
    4225           54 :         if (state->pInfcount > 0 && state->nInfcount > 0)
    4226            3 :             ereport(ERROR,
    4227              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4228              :                      errmsg("interval out of range")));
    4229              : 
    4230           51 :         result = palloc_object(Interval);
    4231           51 :         if (state->pInfcount > 0)
    4232           30 :             INTERVAL_NOEND(result);
    4233              :         else
    4234           21 :             INTERVAL_NOBEGIN(result);
    4235              : 
    4236           51 :         PG_RETURN_INTERVAL_P(result);
    4237              :     }
    4238              : 
    4239           21 :     return DirectFunctionCall2(interval_div,
    4240              :                                IntervalPGetDatum(&state->sumX),
    4241              :                                Float8GetDatum((double) state->N));
    4242              : }
    4243              : 
    4244              : /* sum(interval) aggregate final function */
    4245              : Datum
    4246           81 : interval_sum(PG_FUNCTION_ARGS)
    4247              : {
    4248              :     IntervalAggState *state;
    4249              :     Interval   *result;
    4250              : 
    4251           81 :     state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
    4252              : 
    4253              :     /* If there were no non-null inputs, return NULL */
    4254           81 :     if (state == NULL || IA_TOTAL_COUNT(state) == 0)
    4255            9 :         PG_RETURN_NULL();
    4256              : 
    4257              :     /*
    4258              :      * Aggregating infinities that all have the same sign produces infinity
    4259              :      * with that sign.  Aggregating infinities with different signs results in
    4260              :      * an error.
    4261              :      */
    4262           72 :     if (state->pInfcount > 0 && state->nInfcount > 0)
    4263            3 :         ereport(ERROR,
    4264              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4265              :                  errmsg("interval out of range")));
    4266              : 
    4267           69 :     result = palloc_object(Interval);
    4268              : 
    4269           69 :     if (state->pInfcount > 0)
    4270           30 :         INTERVAL_NOEND(result);
    4271           39 :     else if (state->nInfcount > 0)
    4272           21 :         INTERVAL_NOBEGIN(result);
    4273              :     else
    4274           18 :         memcpy(result, &state->sumX, sizeof(Interval));
    4275              : 
    4276           69 :     PG_RETURN_INTERVAL_P(result);
    4277              : }
    4278              : 
    4279              : /* timestamp_age()
    4280              :  * Calculate time difference while retaining year/month fields.
    4281              :  * Note that this does not result in an accurate absolute time span
    4282              :  *  since year and month are out of context once the arithmetic
    4283              :  *  is done.
    4284              :  */
    4285              : Datum
    4286           18 : timestamp_age(PG_FUNCTION_ARGS)
    4287              : {
    4288           18 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    4289           18 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    4290              :     Interval   *result;
    4291              :     fsec_t      fsec1,
    4292              :                 fsec2;
    4293              :     struct pg_itm tt,
    4294           18 :                *tm = &tt;
    4295              :     struct pg_tm tt1,
    4296           18 :                *tm1 = &tt1;
    4297              :     struct pg_tm tt2,
    4298           18 :                *tm2 = &tt2;
    4299              : 
    4300           18 :     result = palloc_object(Interval);
    4301              : 
    4302              :     /*
    4303              :      * Handle infinities.
    4304              :      *
    4305              :      * We treat anything that amounts to "infinity - infinity" as an error,
    4306              :      * since the interval type has nothing equivalent to NaN.
    4307              :      */
    4308           18 :     if (TIMESTAMP_IS_NOBEGIN(dt1))
    4309              :     {
    4310            6 :         if (TIMESTAMP_IS_NOBEGIN(dt2))
    4311            3 :             ereport(ERROR,
    4312              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4313              :                      errmsg("interval out of range")));
    4314              :         else
    4315            3 :             INTERVAL_NOBEGIN(result);
    4316              :     }
    4317           12 :     else if (TIMESTAMP_IS_NOEND(dt1))
    4318              :     {
    4319            6 :         if (TIMESTAMP_IS_NOEND(dt2))
    4320            3 :             ereport(ERROR,
    4321              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4322              :                      errmsg("interval out of range")));
    4323              :         else
    4324            3 :             INTERVAL_NOEND(result);
    4325              :     }
    4326            6 :     else if (TIMESTAMP_IS_NOBEGIN(dt2))
    4327            3 :         INTERVAL_NOEND(result);
    4328            3 :     else if (TIMESTAMP_IS_NOEND(dt2))
    4329            3 :         INTERVAL_NOBEGIN(result);
    4330            0 :     else if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
    4331            0 :              timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
    4332              :     {
    4333              :         /* form the symbolic difference */
    4334            0 :         tm->tm_usec = fsec1 - fsec2;
    4335            0 :         tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
    4336            0 :         tm->tm_min = tm1->tm_min - tm2->tm_min;
    4337            0 :         tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
    4338            0 :         tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
    4339            0 :         tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
    4340            0 :         tm->tm_year = tm1->tm_year - tm2->tm_year;
    4341              : 
    4342              :         /* flip sign if necessary... */
    4343            0 :         if (dt1 < dt2)
    4344              :         {
    4345            0 :             tm->tm_usec = -tm->tm_usec;
    4346            0 :             tm->tm_sec = -tm->tm_sec;
    4347            0 :             tm->tm_min = -tm->tm_min;
    4348            0 :             tm->tm_hour = -tm->tm_hour;
    4349            0 :             tm->tm_mday = -tm->tm_mday;
    4350            0 :             tm->tm_mon = -tm->tm_mon;
    4351            0 :             tm->tm_year = -tm->tm_year;
    4352              :         }
    4353              : 
    4354              :         /* propagate any negative fields into the next higher field */
    4355            0 :         while (tm->tm_usec < 0)
    4356              :         {
    4357            0 :             tm->tm_usec += USECS_PER_SEC;
    4358            0 :             tm->tm_sec--;
    4359              :         }
    4360              : 
    4361            0 :         while (tm->tm_sec < 0)
    4362              :         {
    4363            0 :             tm->tm_sec += SECS_PER_MINUTE;
    4364            0 :             tm->tm_min--;
    4365              :         }
    4366              : 
    4367            0 :         while (tm->tm_min < 0)
    4368              :         {
    4369            0 :             tm->tm_min += MINS_PER_HOUR;
    4370            0 :             tm->tm_hour--;
    4371              :         }
    4372              : 
    4373            0 :         while (tm->tm_hour < 0)
    4374              :         {
    4375            0 :             tm->tm_hour += HOURS_PER_DAY;
    4376            0 :             tm->tm_mday--;
    4377              :         }
    4378              : 
    4379            0 :         while (tm->tm_mday < 0)
    4380              :         {
    4381            0 :             if (dt1 < dt2)
    4382              :             {
    4383            0 :                 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
    4384            0 :                 tm->tm_mon--;
    4385              :             }
    4386              :             else
    4387              :             {
    4388            0 :                 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
    4389            0 :                 tm->tm_mon--;
    4390              :             }
    4391              :         }
    4392              : 
    4393            0 :         while (tm->tm_mon < 0)
    4394              :         {
    4395            0 :             tm->tm_mon += MONTHS_PER_YEAR;
    4396            0 :             tm->tm_year--;
    4397              :         }
    4398              : 
    4399              :         /* recover sign if necessary... */
    4400            0 :         if (dt1 < dt2)
    4401              :         {
    4402            0 :             tm->tm_usec = -tm->tm_usec;
    4403            0 :             tm->tm_sec = -tm->tm_sec;
    4404            0 :             tm->tm_min = -tm->tm_min;
    4405            0 :             tm->tm_hour = -tm->tm_hour;
    4406            0 :             tm->tm_mday = -tm->tm_mday;
    4407            0 :             tm->tm_mon = -tm->tm_mon;
    4408            0 :             tm->tm_year = -tm->tm_year;
    4409              :         }
    4410              : 
    4411            0 :         if (itm2interval(tm, result) != 0)
    4412            0 :             ereport(ERROR,
    4413              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4414              :                      errmsg("interval out of range")));
    4415              :     }
    4416              :     else
    4417            0 :         ereport(ERROR,
    4418              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4419              :                  errmsg("timestamp out of range")));
    4420              : 
    4421           12 :     PG_RETURN_INTERVAL_P(result);
    4422              : }
    4423              : 
    4424              : 
    4425              : /* timestamptz_age()
    4426              :  * Calculate time difference while retaining year/month fields.
    4427              :  * Note that this does not result in an accurate absolute time span
    4428              :  *  since year and month are out of context once the arithmetic
    4429              :  *  is done.
    4430              :  */
    4431              : Datum
    4432           18 : timestamptz_age(PG_FUNCTION_ARGS)
    4433              : {
    4434           18 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    4435           18 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    4436              :     Interval   *result;
    4437              :     fsec_t      fsec1,
    4438              :                 fsec2;
    4439              :     struct pg_itm tt,
    4440           18 :                *tm = &tt;
    4441              :     struct pg_tm tt1,
    4442           18 :                *tm1 = &tt1;
    4443              :     struct pg_tm tt2,
    4444           18 :                *tm2 = &tt2;
    4445              :     int         tz1;
    4446              :     int         tz2;
    4447              : 
    4448           18 :     result = palloc_object(Interval);
    4449              : 
    4450              :     /*
    4451              :      * Handle infinities.
    4452              :      *
    4453              :      * We treat anything that amounts to "infinity - infinity" as an error,
    4454              :      * since the interval type has nothing equivalent to NaN.
    4455              :      */
    4456           18 :     if (TIMESTAMP_IS_NOBEGIN(dt1))
    4457              :     {
    4458            6 :         if (TIMESTAMP_IS_NOBEGIN(dt2))
    4459            3 :             ereport(ERROR,
    4460              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4461              :                      errmsg("interval out of range")));
    4462              :         else
    4463            3 :             INTERVAL_NOBEGIN(result);
    4464              :     }
    4465           12 :     else if (TIMESTAMP_IS_NOEND(dt1))
    4466              :     {
    4467            6 :         if (TIMESTAMP_IS_NOEND(dt2))
    4468            3 :             ereport(ERROR,
    4469              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4470              :                      errmsg("interval out of range")));
    4471              :         else
    4472            3 :             INTERVAL_NOEND(result);
    4473              :     }
    4474            6 :     else if (TIMESTAMP_IS_NOBEGIN(dt2))
    4475            3 :         INTERVAL_NOEND(result);
    4476            3 :     else if (TIMESTAMP_IS_NOEND(dt2))
    4477            3 :         INTERVAL_NOBEGIN(result);
    4478            0 :     else if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
    4479            0 :              timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
    4480              :     {
    4481              :         /* form the symbolic difference */
    4482            0 :         tm->tm_usec = fsec1 - fsec2;
    4483            0 :         tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
    4484            0 :         tm->tm_min = tm1->tm_min - tm2->tm_min;
    4485            0 :         tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
    4486            0 :         tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
    4487            0 :         tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
    4488            0 :         tm->tm_year = tm1->tm_year - tm2->tm_year;
    4489              : 
    4490              :         /* flip sign if necessary... */
    4491            0 :         if (dt1 < dt2)
    4492              :         {
    4493            0 :             tm->tm_usec = -tm->tm_usec;
    4494            0 :             tm->tm_sec = -tm->tm_sec;
    4495            0 :             tm->tm_min = -tm->tm_min;
    4496            0 :             tm->tm_hour = -tm->tm_hour;
    4497            0 :             tm->tm_mday = -tm->tm_mday;
    4498            0 :             tm->tm_mon = -tm->tm_mon;
    4499            0 :             tm->tm_year = -tm->tm_year;
    4500              :         }
    4501              : 
    4502              :         /* propagate any negative fields into the next higher field */
    4503            0 :         while (tm->tm_usec < 0)
    4504              :         {
    4505            0 :             tm->tm_usec += USECS_PER_SEC;
    4506            0 :             tm->tm_sec--;
    4507              :         }
    4508              : 
    4509            0 :         while (tm->tm_sec < 0)
    4510              :         {
    4511            0 :             tm->tm_sec += SECS_PER_MINUTE;
    4512            0 :             tm->tm_min--;
    4513              :         }
    4514              : 
    4515            0 :         while (tm->tm_min < 0)
    4516              :         {
    4517            0 :             tm->tm_min += MINS_PER_HOUR;
    4518            0 :             tm->tm_hour--;
    4519              :         }
    4520              : 
    4521            0 :         while (tm->tm_hour < 0)
    4522              :         {
    4523            0 :             tm->tm_hour += HOURS_PER_DAY;
    4524            0 :             tm->tm_mday--;
    4525              :         }
    4526              : 
    4527            0 :         while (tm->tm_mday < 0)
    4528              :         {
    4529            0 :             if (dt1 < dt2)
    4530              :             {
    4531            0 :                 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
    4532            0 :                 tm->tm_mon--;
    4533              :             }
    4534              :             else
    4535              :             {
    4536            0 :                 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
    4537            0 :                 tm->tm_mon--;
    4538              :             }
    4539              :         }
    4540              : 
    4541            0 :         while (tm->tm_mon < 0)
    4542              :         {
    4543            0 :             tm->tm_mon += MONTHS_PER_YEAR;
    4544            0 :             tm->tm_year--;
    4545              :         }
    4546              : 
    4547              :         /*
    4548              :          * Note: we deliberately ignore any difference between tz1 and tz2.
    4549              :          */
    4550              : 
    4551              :         /* recover sign if necessary... */
    4552            0 :         if (dt1 < dt2)
    4553              :         {
    4554            0 :             tm->tm_usec = -tm->tm_usec;
    4555            0 :             tm->tm_sec = -tm->tm_sec;
    4556            0 :             tm->tm_min = -tm->tm_min;
    4557            0 :             tm->tm_hour = -tm->tm_hour;
    4558            0 :             tm->tm_mday = -tm->tm_mday;
    4559            0 :             tm->tm_mon = -tm->tm_mon;
    4560            0 :             tm->tm_year = -tm->tm_year;
    4561              :         }
    4562              : 
    4563            0 :         if (itm2interval(tm, result) != 0)
    4564            0 :             ereport(ERROR,
    4565              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4566              :                      errmsg("interval out of range")));
    4567              :     }
    4568              :     else
    4569            0 :         ereport(ERROR,
    4570              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4571              :                  errmsg("timestamp out of range")));
    4572              : 
    4573           12 :     PG_RETURN_INTERVAL_P(result);
    4574              : }
    4575              : 
    4576              : 
    4577              : /*----------------------------------------------------------
    4578              :  *  Conversion operators.
    4579              :  *---------------------------------------------------------*/
    4580              : 
    4581              : 
    4582              : /* timestamp_bin()
    4583              :  * Bin timestamp into specified interval.
    4584              :  */
    4585              : Datum
    4586          138 : timestamp_bin(PG_FUNCTION_ARGS)
    4587              : {
    4588          138 :     Interval   *stride = PG_GETARG_INTERVAL_P(0);
    4589          138 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    4590          138 :     Timestamp   origin = PG_GETARG_TIMESTAMP(2);
    4591              :     Timestamp   result,
    4592              :                 stride_usecs,
    4593              :                 tm_diff,
    4594              :                 tm_modulo,
    4595              :                 tm_delta;
    4596              : 
    4597          138 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4598            0 :         PG_RETURN_TIMESTAMP(timestamp);
    4599              : 
    4600          138 :     if (TIMESTAMP_NOT_FINITE(origin))
    4601            0 :         ereport(ERROR,
    4602              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4603              :                  errmsg("origin out of range")));
    4604              : 
    4605          138 :     if (INTERVAL_NOT_FINITE(stride))
    4606            6 :         ereport(ERROR,
    4607              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4608              :                  errmsg("timestamps cannot be binned into infinite intervals")));
    4609              : 
    4610          132 :     if (stride->month != 0)
    4611            6 :         ereport(ERROR,
    4612              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4613              :                  errmsg("timestamps cannot be binned into intervals containing months or years")));
    4614              : 
    4615          126 :     if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
    4616          123 :         unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
    4617            3 :         ereport(ERROR,
    4618              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4619              :                  errmsg("interval out of range")));
    4620              : 
    4621          123 :     if (stride_usecs <= 0)
    4622            6 :         ereport(ERROR,
    4623              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4624              :                  errmsg("stride must be greater than zero")));
    4625              : 
    4626          117 :     if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
    4627            3 :         ereport(ERROR,
    4628              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4629              :                  errmsg("interval out of range")));
    4630              : 
    4631              :     /* These calculations cannot overflow */
    4632          114 :     tm_modulo = tm_diff % stride_usecs;
    4633          114 :     tm_delta = tm_diff - tm_modulo;
    4634          114 :     result = origin + tm_delta;
    4635              : 
    4636              :     /*
    4637              :      * We want to round towards -infinity, not 0, when tm_diff is negative and
    4638              :      * not a multiple of stride_usecs.  This adjustment *can* cause overflow,
    4639              :      * since the result might now be out of the range origin .. timestamp.
    4640              :      */
    4641          114 :     if (tm_modulo < 0)
    4642              :     {
    4643           39 :         if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
    4644           39 :             !IS_VALID_TIMESTAMP(result))
    4645            3 :             ereport(ERROR,
    4646              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4647              :                      errmsg("timestamp out of range")));
    4648              :     }
    4649              : 
    4650          111 :     PG_RETURN_TIMESTAMP(result);
    4651              : }
    4652              : 
    4653              : /* timestamp_trunc()
    4654              :  * Truncate timestamp to specified units.
    4655              :  */
    4656              : Datum
    4657          705 : timestamp_trunc(PG_FUNCTION_ARGS)
    4658              : {
    4659          705 :     text       *units = PG_GETARG_TEXT_PP(0);
    4660          705 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    4661              :     Timestamp   result;
    4662              :     int         type,
    4663              :                 val;
    4664              :     char       *lowunits;
    4665              :     fsec_t      fsec;
    4666              :     struct pg_tm tt,
    4667          705 :                *tm = &tt;
    4668              : 
    4669          705 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4670          705 :                                             VARSIZE_ANY_EXHDR(units),
    4671              :                                             false);
    4672              : 
    4673          705 :     type = DecodeUnits(0, lowunits, &val);
    4674              : 
    4675          705 :     if (type == UNITS)
    4676              :     {
    4677          702 :         if (TIMESTAMP_NOT_FINITE(timestamp))
    4678              :         {
    4679              :             /*
    4680              :              * Errors thrown here for invalid units should exactly match those
    4681              :              * below, else there will be unexpected discrepancies between
    4682              :              * finite- and infinite-input cases.
    4683              :              */
    4684            6 :             switch (val)
    4685              :             {
    4686            3 :                 case DTK_WEEK:
    4687              :                 case DTK_MILLENNIUM:
    4688              :                 case DTK_CENTURY:
    4689              :                 case DTK_DECADE:
    4690              :                 case DTK_YEAR:
    4691              :                 case DTK_QUARTER:
    4692              :                 case DTK_MONTH:
    4693              :                 case DTK_DAY:
    4694              :                 case DTK_HOUR:
    4695              :                 case DTK_MINUTE:
    4696              :                 case DTK_SECOND:
    4697              :                 case DTK_MILLISEC:
    4698              :                 case DTK_MICROSEC:
    4699            3 :                     PG_RETURN_TIMESTAMP(timestamp);
    4700              :                     break;
    4701            3 :                 default:
    4702            3 :                     ereport(ERROR,
    4703              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4704              :                              errmsg("unit \"%s\" not supported for type %s",
    4705              :                                     lowunits, format_type_be(TIMESTAMPOID))));
    4706              :                     result = 0;
    4707              :             }
    4708              :         }
    4709              : 
    4710          696 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    4711            0 :             ereport(ERROR,
    4712              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4713              :                      errmsg("timestamp out of range")));
    4714              : 
    4715          696 :         switch (val)
    4716              :         {
    4717           15 :             case DTK_WEEK:
    4718              :                 {
    4719              :                     int         woy;
    4720              : 
    4721           15 :                     woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4722              : 
    4723              :                     /*
    4724              :                      * If it is week 52/53 and the month is January, then the
    4725              :                      * week must belong to the previous year. Also, some
    4726              :                      * December dates belong to the next year.
    4727              :                      */
    4728           15 :                     if (woy >= 52 && tm->tm_mon == 1)
    4729            0 :                         --tm->tm_year;
    4730           15 :                     if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
    4731            0 :                         ++tm->tm_year;
    4732           15 :                     isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
    4733           15 :                     tm->tm_hour = 0;
    4734           15 :                     tm->tm_min = 0;
    4735           15 :                     tm->tm_sec = 0;
    4736           15 :                     fsec = 0;
    4737           15 :                     break;
    4738              :                 }
    4739            3 :             case DTK_MILLENNIUM:
    4740              :                 /* see comments in timestamptz_trunc */
    4741            3 :                 if (tm->tm_year > 0)
    4742            3 :                     tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
    4743              :                 else
    4744            0 :                     tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
    4745              :                 pg_fallthrough;
    4746              :             case DTK_CENTURY:
    4747              :                 /* see comments in timestamptz_trunc */
    4748            6 :                 if (tm->tm_year > 0)
    4749            6 :                     tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
    4750              :                 else
    4751            0 :                     tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
    4752              :                 pg_fallthrough;
    4753              :             case DTK_DECADE:
    4754              :                 /* see comments in timestamptz_trunc */
    4755            6 :                 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
    4756              :                 {
    4757            0 :                     if (tm->tm_year > 0)
    4758            0 :                         tm->tm_year = (tm->tm_year / 10) * 10;
    4759              :                     else
    4760            0 :                         tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
    4761              :                 }
    4762              :                 pg_fallthrough;
    4763              :             case DTK_YEAR:
    4764            6 :                 tm->tm_mon = 1;
    4765              :                 pg_fallthrough;
    4766            6 :             case DTK_QUARTER:
    4767            6 :                 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
    4768              :                 pg_fallthrough;
    4769            6 :             case DTK_MONTH:
    4770            6 :                 tm->tm_mday = 1;
    4771              :                 pg_fallthrough;
    4772          618 :             case DTK_DAY:
    4773          618 :                 tm->tm_hour = 0;
    4774              :                 pg_fallthrough;
    4775          630 :             case DTK_HOUR:
    4776          630 :                 tm->tm_min = 0;
    4777              :                 pg_fallthrough;
    4778          642 :             case DTK_MINUTE:
    4779          642 :                 tm->tm_sec = 0;
    4780              :                 pg_fallthrough;
    4781          654 :             case DTK_SECOND:
    4782          654 :                 fsec = 0;
    4783          654 :                 break;
    4784              : 
    4785           12 :             case DTK_MILLISEC:
    4786           12 :                 fsec = (fsec / 1000) * 1000;
    4787           12 :                 break;
    4788              : 
    4789           12 :             case DTK_MICROSEC:
    4790           12 :                 break;
    4791              : 
    4792            3 :             default:
    4793            3 :                 ereport(ERROR,
    4794              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4795              :                          errmsg("unit \"%s\" not supported for type %s",
    4796              :                                 lowunits, format_type_be(TIMESTAMPOID))));
    4797              :                 result = 0;
    4798              :         }
    4799              : 
    4800          693 :         if (tm2timestamp(tm, fsec, NULL, &result) != 0)
    4801            0 :             ereport(ERROR,
    4802              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4803              :                      errmsg("timestamp out of range")));
    4804              :     }
    4805              :     else
    4806              :     {
    4807            3 :         ereport(ERROR,
    4808              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4809              :                  errmsg("unit \"%s\" not recognized for type %s",
    4810              :                         lowunits, format_type_be(TIMESTAMPOID))));
    4811              :         result = 0;
    4812              :     }
    4813              : 
    4814          693 :     PG_RETURN_TIMESTAMP(result);
    4815              : }
    4816              : 
    4817              : /* timestamptz_bin()
    4818              :  * Bin timestamptz into specified interval using specified origin.
    4819              :  */
    4820              : Datum
    4821           66 : timestamptz_bin(PG_FUNCTION_ARGS)
    4822              : {
    4823           66 :     Interval   *stride = PG_GETARG_INTERVAL_P(0);
    4824           66 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    4825           66 :     TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
    4826              :     TimestampTz result,
    4827              :                 stride_usecs,
    4828              :                 tm_diff,
    4829              :                 tm_modulo,
    4830              :                 tm_delta;
    4831              : 
    4832           66 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4833            0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    4834              : 
    4835           66 :     if (TIMESTAMP_NOT_FINITE(origin))
    4836            0 :         ereport(ERROR,
    4837              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4838              :                  errmsg("origin out of range")));
    4839              : 
    4840           66 :     if (INTERVAL_NOT_FINITE(stride))
    4841            0 :         ereport(ERROR,
    4842              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4843              :                  errmsg("timestamps cannot be binned into infinite intervals")));
    4844              : 
    4845           66 :     if (stride->month != 0)
    4846            6 :         ereport(ERROR,
    4847              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4848              :                  errmsg("timestamps cannot be binned into intervals containing months or years")));
    4849              : 
    4850           60 :     if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
    4851           57 :         unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
    4852            3 :         ereport(ERROR,
    4853              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4854              :                  errmsg("interval out of range")));
    4855              : 
    4856           57 :     if (stride_usecs <= 0)
    4857            6 :         ereport(ERROR,
    4858              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4859              :                  errmsg("stride must be greater than zero")));
    4860              : 
    4861           51 :     if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
    4862            3 :         ereport(ERROR,
    4863              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4864              :                  errmsg("interval out of range")));
    4865              : 
    4866              :     /* These calculations cannot overflow */
    4867           48 :     tm_modulo = tm_diff % stride_usecs;
    4868           48 :     tm_delta = tm_diff - tm_modulo;
    4869           48 :     result = origin + tm_delta;
    4870              : 
    4871              :     /*
    4872              :      * We want to round towards -infinity, not 0, when tm_diff is negative and
    4873              :      * not a multiple of stride_usecs.  This adjustment *can* cause overflow,
    4874              :      * since the result might now be out of the range origin .. timestamp.
    4875              :      */
    4876           48 :     if (tm_modulo < 0)
    4877              :     {
    4878            3 :         if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
    4879            3 :             !IS_VALID_TIMESTAMP(result))
    4880            3 :             ereport(ERROR,
    4881              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4882              :                      errmsg("timestamp out of range")));
    4883              :     }
    4884              : 
    4885           45 :     PG_RETURN_TIMESTAMPTZ(result);
    4886              : }
    4887              : 
    4888              : /*
    4889              :  * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
    4890              :  *
    4891              :  * tzp identifies the zone to truncate with respect to.  We assume
    4892              :  * infinite timestamps have already been rejected.
    4893              :  */
    4894              : static TimestampTz
    4895          675 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
    4896              : {
    4897              :     TimestampTz result;
    4898              :     int         tz;
    4899              :     int         type,
    4900              :                 val;
    4901          675 :     bool        redotz = false;
    4902              :     char       *lowunits;
    4903              :     fsec_t      fsec;
    4904              :     struct pg_tm tt,
    4905          675 :                *tm = &tt;
    4906              : 
    4907          675 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4908          675 :                                             VARSIZE_ANY_EXHDR(units),
    4909              :                                             false);
    4910              : 
    4911          675 :     type = DecodeUnits(0, lowunits, &val);
    4912              : 
    4913          675 :     if (type == UNITS)
    4914              :     {
    4915          669 :         if (TIMESTAMP_NOT_FINITE(timestamp))
    4916              :         {
    4917              :             /*
    4918              :              * Errors thrown here for invalid units should exactly match those
    4919              :              * below, else there will be unexpected discrepancies between
    4920              :              * finite- and infinite-input cases.
    4921              :              */
    4922           12 :             switch (val)
    4923              :             {
    4924            6 :                 case DTK_WEEK:
    4925              :                 case DTK_MILLENNIUM:
    4926              :                 case DTK_CENTURY:
    4927              :                 case DTK_DECADE:
    4928              :                 case DTK_YEAR:
    4929              :                 case DTK_QUARTER:
    4930              :                 case DTK_MONTH:
    4931              :                 case DTK_DAY:
    4932              :                 case DTK_HOUR:
    4933              :                 case DTK_MINUTE:
    4934              :                 case DTK_SECOND:
    4935              :                 case DTK_MILLISEC:
    4936              :                 case DTK_MICROSEC:
    4937            6 :                     return timestamp;
    4938              :                     break;
    4939              : 
    4940            6 :                 default:
    4941            6 :                     ereport(ERROR,
    4942              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4943              :                              errmsg("unit \"%s\" not supported for type %s",
    4944              :                                     lowunits, format_type_be(TIMESTAMPTZOID))));
    4945              :                     result = 0;
    4946              :             }
    4947              :         }
    4948              : 
    4949          657 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
    4950            0 :             ereport(ERROR,
    4951              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4952              :                      errmsg("timestamp out of range")));
    4953              : 
    4954          657 :         switch (val)
    4955              :         {
    4956            3 :             case DTK_WEEK:
    4957              :                 {
    4958              :                     int         woy;
    4959              : 
    4960            3 :                     woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4961              : 
    4962              :                     /*
    4963              :                      * If it is week 52/53 and the month is January, then the
    4964              :                      * week must belong to the previous year. Also, some
    4965              :                      * December dates belong to the next year.
    4966              :                      */
    4967            3 :                     if (woy >= 52 && tm->tm_mon == 1)
    4968            0 :                         --tm->tm_year;
    4969            3 :                     if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
    4970            0 :                         ++tm->tm_year;
    4971            3 :                     isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
    4972            3 :                     tm->tm_hour = 0;
    4973            3 :                     tm->tm_min = 0;
    4974            3 :                     tm->tm_sec = 0;
    4975            3 :                     fsec = 0;
    4976            3 :                     redotz = true;
    4977            3 :                     break;
    4978              :                 }
    4979              :                 /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
    4980            3 :             case DTK_MILLENNIUM:
    4981              : 
    4982              :                 /*
    4983              :                  * truncating to the millennium? what is this supposed to
    4984              :                  * mean? let us put the first year of the millennium... i.e.
    4985              :                  * -1000, 1, 1001, 2001...
    4986              :                  */
    4987            3 :                 if (tm->tm_year > 0)
    4988            3 :                     tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
    4989              :                 else
    4990            0 :                     tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
    4991              :                 pg_fallthrough;
    4992              :             case DTK_CENTURY:
    4993              :                 /* truncating to the century? as above: -100, 1, 101... */
    4994           15 :                 if (tm->tm_year > 0)
    4995           12 :                     tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
    4996              :                 else
    4997            3 :                     tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
    4998              :                 pg_fallthrough;
    4999              :             case DTK_DECADE:
    5000              : 
    5001              :                 /*
    5002              :                  * truncating to the decade? first year of the decade. must
    5003              :                  * not be applied if year was truncated before!
    5004              :                  */
    5005           24 :                 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
    5006              :                 {
    5007            9 :                     if (tm->tm_year > 0)
    5008            6 :                         tm->tm_year = (tm->tm_year / 10) * 10;
    5009              :                     else
    5010            3 :                         tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
    5011              :                 }
    5012              :                 pg_fallthrough;
    5013              :             case DTK_YEAR:
    5014           24 :                 tm->tm_mon = 1;
    5015              :                 pg_fallthrough;
    5016           24 :             case DTK_QUARTER:
    5017           24 :                 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
    5018              :                 pg_fallthrough;
    5019           24 :             case DTK_MONTH:
    5020           24 :                 tm->tm_mday = 1;
    5021              :                 pg_fallthrough;
    5022          636 :             case DTK_DAY:
    5023          636 :                 tm->tm_hour = 0;
    5024          636 :                 redotz = true;  /* for all cases >= DAY */
    5025              :                 pg_fallthrough;
    5026          639 :             case DTK_HOUR:
    5027          639 :                 tm->tm_min = 0;
    5028              :                 pg_fallthrough;
    5029          642 :             case DTK_MINUTE:
    5030          642 :                 tm->tm_sec = 0;
    5031              :                 pg_fallthrough;
    5032          645 :             case DTK_SECOND:
    5033          645 :                 fsec = 0;
    5034          645 :                 break;
    5035            3 :             case DTK_MILLISEC:
    5036            3 :                 fsec = (fsec / 1000) * 1000;
    5037            3 :                 break;
    5038            3 :             case DTK_MICROSEC:
    5039            3 :                 break;
    5040              : 
    5041            3 :             default:
    5042            3 :                 ereport(ERROR,
    5043              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5044              :                          errmsg("unit \"%s\" not supported for type %s",
    5045              :                                 lowunits, format_type_be(TIMESTAMPTZOID))));
    5046              :                 result = 0;
    5047              :         }
    5048              : 
    5049          654 :         if (redotz)
    5050          639 :             tz = DetermineTimeZoneOffset(tm, tzp);
    5051              : 
    5052          654 :         if (tm2timestamp(tm, fsec, &tz, &result) != 0)
    5053            0 :             ereport(ERROR,
    5054              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5055              :                      errmsg("timestamp out of range")));
    5056              :     }
    5057              :     else
    5058              :     {
    5059            6 :         ereport(ERROR,
    5060              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5061              :                  errmsg("unit \"%s\" not recognized for type %s",
    5062              :                         lowunits, format_type_be(TIMESTAMPTZOID))));
    5063              :         result = 0;
    5064              :     }
    5065              : 
    5066          654 :     return result;
    5067              : }
    5068              : 
    5069              : /* timestamptz_trunc()
    5070              :  * Truncate timestamptz to specified units in session timezone.
    5071              :  */
    5072              : Datum
    5073          639 : timestamptz_trunc(PG_FUNCTION_ARGS)
    5074              : {
    5075          639 :     text       *units = PG_GETARG_TEXT_PP(0);
    5076          639 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    5077              :     TimestampTz result;
    5078              : 
    5079          639 :     result = timestamptz_trunc_internal(units, timestamp, session_timezone);
    5080              : 
    5081          630 :     PG_RETURN_TIMESTAMPTZ(result);
    5082              : }
    5083              : 
    5084              : /* timestamptz_trunc_zone()
    5085              :  * Truncate timestamptz to specified units in specified timezone.
    5086              :  */
    5087              : Datum
    5088           36 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
    5089              : {
    5090           36 :     text       *units = PG_GETARG_TEXT_PP(0);
    5091           36 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    5092           36 :     text       *zone = PG_GETARG_TEXT_PP(2);
    5093              :     TimestampTz result;
    5094              :     pg_tz      *tzp;
    5095              : 
    5096              :     /*
    5097              :      * Look up the requested timezone.
    5098              :      */
    5099           36 :     tzp = lookup_timezone(zone);
    5100              : 
    5101           36 :     result = timestamptz_trunc_internal(units, timestamp, tzp);
    5102              : 
    5103           30 :     PG_RETURN_TIMESTAMPTZ(result);
    5104              : }
    5105              : 
    5106              : /* interval_trunc()
    5107              :  * Extract specified field from interval.
    5108              :  */
    5109              : Datum
    5110           12 : interval_trunc(PG_FUNCTION_ARGS)
    5111              : {
    5112           12 :     text       *units = PG_GETARG_TEXT_PP(0);
    5113           12 :     Interval   *interval = PG_GETARG_INTERVAL_P(1);
    5114              :     Interval   *result;
    5115              :     int         type,
    5116              :                 val;
    5117              :     char       *lowunits;
    5118              :     struct pg_itm tt,
    5119           12 :                *tm = &tt;
    5120              : 
    5121           12 :     result = palloc_object(Interval);
    5122              : 
    5123           12 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    5124           12 :                                             VARSIZE_ANY_EXHDR(units),
    5125              :                                             false);
    5126              : 
    5127           12 :     type = DecodeUnits(0, lowunits, &val);
    5128              : 
    5129           12 :     if (type == UNITS)
    5130              :     {
    5131            9 :         if (INTERVAL_NOT_FINITE(interval))
    5132              :         {
    5133              :             /*
    5134              :              * Errors thrown here for invalid units should exactly match those
    5135              :              * below, else there will be unexpected discrepancies between
    5136              :              * finite- and infinite-input cases.
    5137              :              */
    5138            9 :             switch (val)
    5139              :             {
    5140            6 :                 case DTK_MILLENNIUM:
    5141              :                 case DTK_CENTURY:
    5142              :                 case DTK_DECADE:
    5143              :                 case DTK_YEAR:
    5144              :                 case DTK_QUARTER:
    5145              :                 case DTK_MONTH:
    5146              :                 case DTK_DAY:
    5147              :                 case DTK_HOUR:
    5148              :                 case DTK_MINUTE:
    5149              :                 case DTK_SECOND:
    5150              :                 case DTK_MILLISEC:
    5151              :                 case DTK_MICROSEC:
    5152            6 :                     memcpy(result, interval, sizeof(Interval));
    5153            6 :                     PG_RETURN_INTERVAL_P(result);
    5154              :                     break;
    5155              : 
    5156            3 :                 default:
    5157            3 :                     ereport(ERROR,
    5158              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5159              :                              errmsg("unit \"%s\" not supported for type %s",
    5160              :                                     lowunits, format_type_be(INTERVALOID)),
    5161              :                              (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
    5162              :                     result = NULL;
    5163              :             }
    5164              :         }
    5165              : 
    5166            0 :         interval2itm(*interval, tm);
    5167            0 :         switch (val)
    5168              :         {
    5169            0 :             case DTK_MILLENNIUM:
    5170              :                 /* caution: C division may have negative remainder */
    5171            0 :                 tm->tm_year = (tm->tm_year / 1000) * 1000;
    5172              :                 pg_fallthrough;
    5173            0 :             case DTK_CENTURY:
    5174              :                 /* caution: C division may have negative remainder */
    5175            0 :                 tm->tm_year = (tm->tm_year / 100) * 100;
    5176              :                 pg_fallthrough;
    5177            0 :             case DTK_DECADE:
    5178              :                 /* caution: C division may have negative remainder */
    5179            0 :                 tm->tm_year = (tm->tm_year / 10) * 10;
    5180              :                 pg_fallthrough;
    5181            0 :             case DTK_YEAR:
    5182            0 :                 tm->tm_mon = 0;
    5183              :                 pg_fallthrough;
    5184            0 :             case DTK_QUARTER:
    5185            0 :                 tm->tm_mon = 3 * (tm->tm_mon / 3);
    5186              :                 pg_fallthrough;
    5187            0 :             case DTK_MONTH:
    5188            0 :                 tm->tm_mday = 0;
    5189              :                 pg_fallthrough;
    5190            0 :             case DTK_DAY:
    5191            0 :                 tm->tm_hour = 0;
    5192              :                 pg_fallthrough;
    5193            0 :             case DTK_HOUR:
    5194            0 :                 tm->tm_min = 0;
    5195              :                 pg_fallthrough;
    5196            0 :             case DTK_MINUTE:
    5197            0 :                 tm->tm_sec = 0;
    5198              :                 pg_fallthrough;
    5199            0 :             case DTK_SECOND:
    5200            0 :                 tm->tm_usec = 0;
    5201            0 :                 break;
    5202            0 :             case DTK_MILLISEC:
    5203            0 :                 tm->tm_usec = (tm->tm_usec / 1000) * 1000;
    5204            0 :                 break;
    5205            0 :             case DTK_MICROSEC:
    5206            0 :                 break;
    5207              : 
    5208            0 :             default:
    5209            0 :                 ereport(ERROR,
    5210              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5211              :                          errmsg("unit \"%s\" not supported for type %s",
    5212              :                                 lowunits, format_type_be(INTERVALOID)),
    5213              :                          (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
    5214              :         }
    5215              : 
    5216            0 :         if (itm2interval(tm, result) != 0)
    5217            0 :             ereport(ERROR,
    5218              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5219              :                      errmsg("interval out of range")));
    5220              :     }
    5221              :     else
    5222              :     {
    5223            3 :         ereport(ERROR,
    5224              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5225              :                  errmsg("unit \"%s\" not recognized for type %s",
    5226              :                         lowunits, format_type_be(INTERVALOID))));
    5227              :     }
    5228              : 
    5229            0 :     PG_RETURN_INTERVAL_P(result);
    5230              : }
    5231              : 
    5232              : /* isoweek2j()
    5233              :  *
    5234              :  *  Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
    5235              :  *  Julian days are used to convert between ISO week dates and Gregorian dates.
    5236              :  *
    5237              :  *  XXX: This function has integer overflow hazards, but restructuring it to
    5238              :  *  work with the soft-error handling that its callers do is likely more
    5239              :  *  trouble than it's worth.
    5240              :  */
    5241              : int
    5242          795 : isoweek2j(int year, int week)
    5243              : {
    5244              :     int         day0,
    5245              :                 day4;
    5246              : 
    5247              :     /* fourth day of current year */
    5248          795 :     day4 = date2j(year, 1, 4);
    5249              : 
    5250              :     /* day0 == offset to first day of week (Monday) */
    5251          795 :     day0 = j2day(day4 - 1);
    5252              : 
    5253          795 :     return ((week - 1) * 7) + (day4 - day0);
    5254              : }
    5255              : 
    5256              : /* isoweek2date()
    5257              :  * Convert ISO week of year number to date.
    5258              :  * The year field must be specified with the ISO year!
    5259              :  * karel 2000/08/07
    5260              :  */
    5261              : void
    5262           18 : isoweek2date(int woy, int *year, int *mon, int *mday)
    5263              : {
    5264           18 :     j2date(isoweek2j(*year, woy), year, mon, mday);
    5265           18 : }
    5266              : 
    5267              : /* isoweekdate2date()
    5268              :  *
    5269              :  *  Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
    5270              :  *  Gregorian day of week sent so weekday strings can be supplied.
    5271              :  *  Populates year, mon, and mday with the correct Gregorian values.
    5272              :  *  year must be passed in as the ISO year.
    5273              :  */
    5274              : void
    5275           12 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
    5276              : {
    5277              :     int         jday;
    5278              : 
    5279           12 :     jday = isoweek2j(*year, isoweek);
    5280              :     /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
    5281           12 :     if (wday > 1)
    5282            0 :         jday += wday - 2;
    5283              :     else
    5284           12 :         jday += 6;
    5285           12 :     j2date(jday, year, mon, mday);
    5286           12 : }
    5287              : 
    5288              : /* date2isoweek()
    5289              :  *
    5290              :  *  Returns ISO week number of year.
    5291              :  */
    5292              : int
    5293         1212 : date2isoweek(int year, int mon, int mday)
    5294              : {
    5295              :     int         day0,
    5296              :                 day4,
    5297              :                 dayn,
    5298              :                 week;
    5299              : 
    5300              :     /* current day */
    5301         1212 :     dayn = date2j(year, mon, mday);
    5302              : 
    5303              :     /* fourth day of current year */
    5304         1212 :     day4 = date2j(year, 1, 4);
    5305              : 
    5306              :     /* day0 == offset to first day of week (Monday) */
    5307         1212 :     day0 = j2day(day4 - 1);
    5308              : 
    5309              :     /*
    5310              :      * We need the first week containing a Thursday, otherwise this day falls
    5311              :      * into the previous year for purposes of counting weeks
    5312              :      */
    5313         1212 :     if (dayn < day4 - day0)
    5314              :     {
    5315           18 :         day4 = date2j(year - 1, 1, 4);
    5316              : 
    5317              :         /* day0 == offset to first day of week (Monday) */
    5318           18 :         day0 = j2day(day4 - 1);
    5319              :     }
    5320              : 
    5321         1212 :     week = (dayn - (day4 - day0)) / 7 + 1;
    5322              : 
    5323              :     /*
    5324              :      * Sometimes the last few days in a year will fall into the first week of
    5325              :      * the next year, so check for this.
    5326              :      */
    5327         1212 :     if (week >= 52)
    5328              :     {
    5329          135 :         day4 = date2j(year + 1, 1, 4);
    5330              : 
    5331              :         /* day0 == offset to first day of week (Monday) */
    5332          135 :         day0 = j2day(day4 - 1);
    5333              : 
    5334          135 :         if (dayn >= day4 - day0)
    5335           81 :             week = (dayn - (day4 - day0)) / 7 + 1;
    5336              :     }
    5337              : 
    5338         1212 :     return week;
    5339              : }
    5340              : 
    5341              : 
    5342              : /* date2isoyear()
    5343              :  *
    5344              :  *  Returns ISO 8601 year number.
    5345              :  *  Note: zero or negative results follow the year-zero-exists convention.
    5346              :  */
    5347              : int
    5348         7293 : date2isoyear(int year, int mon, int mday)
    5349              : {
    5350              :     int         day0,
    5351              :                 day4,
    5352              :                 dayn,
    5353              :                 week;
    5354              : 
    5355              :     /* current day */
    5356         7293 :     dayn = date2j(year, mon, mday);
    5357              : 
    5358              :     /* fourth day of current year */
    5359         7293 :     day4 = date2j(year, 1, 4);
    5360              : 
    5361              :     /* day0 == offset to first day of week (Monday) */
    5362         7293 :     day0 = j2day(day4 - 1);
    5363              : 
    5364              :     /*
    5365              :      * We need the first week containing a Thursday, otherwise this day falls
    5366              :      * into the previous year for purposes of counting weeks
    5367              :      */
    5368         7293 :     if (dayn < day4 - day0)
    5369              :     {
    5370          114 :         day4 = date2j(year - 1, 1, 4);
    5371              : 
    5372              :         /* day0 == offset to first day of week (Monday) */
    5373          114 :         day0 = j2day(day4 - 1);
    5374              : 
    5375          114 :         year--;
    5376              :     }
    5377              : 
    5378         7293 :     week = (dayn - (day4 - day0)) / 7 + 1;
    5379              : 
    5380              :     /*
    5381              :      * Sometimes the last few days in a year will fall into the first week of
    5382              :      * the next year, so check for this.
    5383              :      */
    5384         7293 :     if (week >= 52)
    5385              :     {
    5386          855 :         day4 = date2j(year + 1, 1, 4);
    5387              : 
    5388              :         /* day0 == offset to first day of week (Monday) */
    5389          855 :         day0 = j2day(day4 - 1);
    5390              : 
    5391          855 :         if (dayn >= day4 - day0)
    5392          513 :             year++;
    5393              :     }
    5394              : 
    5395         7293 :     return year;
    5396              : }
    5397              : 
    5398              : 
    5399              : /* date2isoyearday()
    5400              :  *
    5401              :  *  Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
    5402              :  *  Possible return values are 1 through 371 (364 in non-leap years).
    5403              :  */
    5404              : int
    5405          762 : date2isoyearday(int year, int mon, int mday)
    5406              : {
    5407          762 :     return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
    5408              : }
    5409              : 
    5410              : /*
    5411              :  * NonFiniteTimestampTzPart
    5412              :  *
    5413              :  *  Used by timestamp_part and timestamptz_part when extracting from infinite
    5414              :  *  timestamp[tz].  Returns +/-Infinity if that is the appropriate result,
    5415              :  *  otherwise returns zero (which should be taken as meaning to return NULL).
    5416              :  *
    5417              :  *  Errors thrown here for invalid units should exactly match those that
    5418              :  *  would be thrown in the calling functions, else there will be unexpected
    5419              :  *  discrepancies between finite- and infinite-input cases.
    5420              :  */
    5421              : static float8
    5422          306 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
    5423              :                          bool isNegative, bool isTz)
    5424              : {
    5425          306 :     if ((type != UNITS) && (type != RESERV))
    5426            0 :         ereport(ERROR,
    5427              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5428              :                  errmsg("unit \"%s\" not recognized for type %s",
    5429              :                         lowunits,
    5430              :                         format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
    5431              : 
    5432          306 :     switch (unit)
    5433              :     {
    5434              :             /* Oscillating units */
    5435          198 :         case DTK_MICROSEC:
    5436              :         case DTK_MILLISEC:
    5437              :         case DTK_SECOND:
    5438              :         case DTK_MINUTE:
    5439              :         case DTK_HOUR:
    5440              :         case DTK_DAY:
    5441              :         case DTK_MONTH:
    5442              :         case DTK_QUARTER:
    5443              :         case DTK_WEEK:
    5444              :         case DTK_DOW:
    5445              :         case DTK_ISODOW:
    5446              :         case DTK_DOY:
    5447              :         case DTK_TZ:
    5448              :         case DTK_TZ_MINUTE:
    5449              :         case DTK_TZ_HOUR:
    5450          198 :             return 0.0;
    5451              : 
    5452              :             /* Monotonically-increasing units */
    5453          108 :         case DTK_YEAR:
    5454              :         case DTK_DECADE:
    5455              :         case DTK_CENTURY:
    5456              :         case DTK_MILLENNIUM:
    5457              :         case DTK_JULIAN:
    5458              :         case DTK_ISOYEAR:
    5459              :         case DTK_EPOCH:
    5460          108 :             if (isNegative)
    5461           54 :                 return -get_float8_infinity();
    5462              :             else
    5463           54 :                 return get_float8_infinity();
    5464              : 
    5465            0 :         default:
    5466            0 :             ereport(ERROR,
    5467              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5468              :                      errmsg("unit \"%s\" not supported for type %s",
    5469              :                             lowunits,
    5470              :                             format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
    5471              :             return 0.0;         /* keep compiler quiet */
    5472              :     }
    5473              : }
    5474              : 
    5475              : /* timestamp_part() and extract_timestamp()
    5476              :  * Extract specified field from timestamp.
    5477              :  */
    5478              : static Datum
    5479         5361 : timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
    5480              : {
    5481         5361 :     text       *units = PG_GETARG_TEXT_PP(0);
    5482         5361 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    5483              :     int64       intresult;
    5484              :     Timestamp   epoch;
    5485              :     int         type,
    5486              :                 val;
    5487              :     char       *lowunits;
    5488              :     fsec_t      fsec;
    5489              :     struct pg_tm tt,
    5490         5361 :                *tm = &tt;
    5491              : 
    5492         5361 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    5493         5361 :                                             VARSIZE_ANY_EXHDR(units),
    5494              :                                             false);
    5495              : 
    5496         5361 :     type = DecodeUnits(0, lowunits, &val);
    5497         5361 :     if (type == UNKNOWN_FIELD)
    5498         1857 :         type = DecodeSpecial(0, lowunits, &val);
    5499              : 
    5500         5361 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5501              :     {
    5502          144 :         double      r = NonFiniteTimestampTzPart(type, val, lowunits,
    5503              :                                                  TIMESTAMP_IS_NOBEGIN(timestamp),
    5504              :                                                  false);
    5505              : 
    5506          144 :         if (r != 0.0)
    5507              :         {
    5508           54 :             if (retnumeric)
    5509              :             {
    5510           12 :                 if (r < 0)
    5511            6 :                     return DirectFunctionCall3(numeric_in,
    5512              :                                                CStringGetDatum("-Infinity"),
    5513              :                                                ObjectIdGetDatum(InvalidOid),
    5514              :                                                Int32GetDatum(-1));
    5515            6 :                 else if (r > 0)
    5516            6 :                     return DirectFunctionCall3(numeric_in,
    5517              :                                                CStringGetDatum("Infinity"),
    5518              :                                                ObjectIdGetDatum(InvalidOid),
    5519              :                                                Int32GetDatum(-1));
    5520              :             }
    5521              :             else
    5522           42 :                 PG_RETURN_FLOAT8(r);
    5523              :         }
    5524              :         else
    5525           90 :             PG_RETURN_NULL();
    5526              :     }
    5527              : 
    5528         5217 :     if (type == UNITS)
    5529              :     {
    5530         4782 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    5531            0 :             ereport(ERROR,
    5532              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5533              :                      errmsg("timestamp out of range")));
    5534              : 
    5535         4782 :         switch (val)
    5536              :         {
    5537          378 :             case DTK_MICROSEC:
    5538          378 :                 intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
    5539          378 :                 break;
    5540              : 
    5541          378 :             case DTK_MILLISEC:
    5542          378 :                 if (retnumeric)
    5543              :                     /*---
    5544              :                      * tm->tm_sec * 1000 + fsec / 1000
    5545              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1000
    5546              :                      */
    5547          189 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
    5548              :                 else
    5549          189 :                     PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
    5550              :                 break;
    5551              : 
    5552          378 :             case DTK_SECOND:
    5553          378 :                 if (retnumeric)
    5554              :                     /*---
    5555              :                      * tm->tm_sec + fsec / 1'000'000
    5556              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
    5557              :                      */
    5558          189 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
    5559              :                 else
    5560          189 :                     PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
    5561              :                 break;
    5562              : 
    5563          189 :             case DTK_MINUTE:
    5564          189 :                 intresult = tm->tm_min;
    5565          189 :                 break;
    5566              : 
    5567          189 :             case DTK_HOUR:
    5568          189 :                 intresult = tm->tm_hour;
    5569          189 :                 break;
    5570              : 
    5571          237 :             case DTK_DAY:
    5572          237 :                 intresult = tm->tm_mday;
    5573          237 :                 break;
    5574              : 
    5575          237 :             case DTK_MONTH:
    5576          237 :                 intresult = tm->tm_mon;
    5577          237 :                 break;
    5578              : 
    5579          237 :             case DTK_QUARTER:
    5580          237 :                 intresult = (tm->tm_mon - 1) / 3 + 1;
    5581          237 :                 break;
    5582              : 
    5583          237 :             case DTK_WEEK:
    5584          237 :                 intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    5585          237 :                 break;
    5586              : 
    5587          237 :             case DTK_YEAR:
    5588          237 :                 if (tm->tm_year > 0)
    5589          231 :                     intresult = tm->tm_year;
    5590              :                 else
    5591              :                     /* there is no year 0, just 1 BC and 1 AD */
    5592            6 :                     intresult = tm->tm_year - 1;
    5593          237 :                 break;
    5594              : 
    5595          237 :             case DTK_DECADE:
    5596              : 
    5597              :                 /*
    5598              :                  * what is a decade wrt dates? let us assume that decade 199
    5599              :                  * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
    5600              :                  * is 11 BC thru 2 BC...
    5601              :                  */
    5602          237 :                 if (tm->tm_year >= 0)
    5603          231 :                     intresult = tm->tm_year / 10;
    5604              :                 else
    5605            6 :                     intresult = -((8 - (tm->tm_year - 1)) / 10);
    5606          237 :                 break;
    5607              : 
    5608          237 :             case DTK_CENTURY:
    5609              : 
    5610              :                 /* ----
    5611              :                  * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
    5612              :                  * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
    5613              :                  * there is no number 0 century.
    5614              :                  * ----
    5615              :                  */
    5616          237 :                 if (tm->tm_year > 0)
    5617          231 :                     intresult = (tm->tm_year + 99) / 100;
    5618              :                 else
    5619              :                     /* caution: C division may have negative remainder */
    5620            6 :                     intresult = -((99 - (tm->tm_year - 1)) / 100);
    5621          237 :                 break;
    5622              : 
    5623          237 :             case DTK_MILLENNIUM:
    5624              :                 /* see comments above. */
    5625          237 :                 if (tm->tm_year > 0)
    5626          231 :                     intresult = (tm->tm_year + 999) / 1000;
    5627              :                 else
    5628            6 :                     intresult = -((999 - (tm->tm_year - 1)) / 1000);
    5629          237 :                 break;
    5630              : 
    5631          426 :             case DTK_JULIAN:
    5632          426 :                 if (retnumeric)
    5633          189 :                     PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
    5634              :                                                        numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
    5635              :                                                                         int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
    5636              :                                                                         NULL),
    5637              :                                                        NULL));
    5638              :                 else
    5639          237 :                     PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
    5640              :                                      ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
    5641              :                                       tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
    5642              :                 break;
    5643              : 
    5644          237 :             case DTK_ISOYEAR:
    5645          237 :                 intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
    5646              :                 /* Adjust BC years */
    5647          237 :                 if (intresult <= 0)
    5648            6 :                     intresult -= 1;
    5649          237 :                 break;
    5650              : 
    5651          474 :             case DTK_DOW:
    5652              :             case DTK_ISODOW:
    5653          474 :                 intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
    5654          474 :                 if (val == DTK_ISODOW && intresult == 0)
    5655           15 :                     intresult = 7;
    5656          474 :                 break;
    5657              : 
    5658          237 :             case DTK_DOY:
    5659          237 :                 intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
    5660          237 :                              - date2j(tm->tm_year, 1, 1) + 1);
    5661          237 :                 break;
    5662              : 
    5663            0 :             case DTK_TZ:
    5664              :             case DTK_TZ_MINUTE:
    5665              :             case DTK_TZ_HOUR:
    5666              :             default:
    5667            0 :                 ereport(ERROR,
    5668              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5669              :                          errmsg("unit \"%s\" not supported for type %s",
    5670              :                                 lowunits, format_type_be(TIMESTAMPOID))));
    5671              :                 intresult = 0;
    5672              :         }
    5673              :     }
    5674          435 :     else if (type == RESERV)
    5675              :     {
    5676          435 :         switch (val)
    5677              :         {
    5678          435 :             case DTK_EPOCH:
    5679          435 :                 epoch = SetEpochTimestamp();
    5680              :                 /* (timestamp - epoch) / 1000000 */
    5681          435 :                 if (retnumeric)
    5682              :                 {
    5683              :                     Numeric     result;
    5684              : 
    5685          195 :                     if (timestamp < (PG_INT64_MAX + epoch))
    5686          192 :                         result = int64_div_fast_to_numeric(timestamp - epoch, 6);
    5687              :                     else
    5688              :                     {
    5689            3 :                         result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
    5690              :                                                                    int64_to_numeric(epoch),
    5691              :                                                                    NULL),
    5692              :                                                   int64_to_numeric(1000000),
    5693              :                                                   NULL);
    5694            3 :                         result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
    5695              :                                                                      NumericGetDatum(result),
    5696              :                                                                      Int32GetDatum(6)));
    5697              :                     }
    5698          195 :                     PG_RETURN_NUMERIC(result);
    5699              :                 }
    5700              :                 else
    5701              :                 {
    5702              :                     float8      result;
    5703              : 
    5704              :                     /* try to avoid precision loss in subtraction */
    5705          240 :                     if (timestamp < (PG_INT64_MAX + epoch))
    5706          237 :                         result = (timestamp - epoch) / 1000000.0;
    5707              :                     else
    5708            3 :                         result = ((float8) timestamp - epoch) / 1000000.0;
    5709          240 :                     PG_RETURN_FLOAT8(result);
    5710              :                 }
    5711              :                 break;
    5712              : 
    5713            0 :             default:
    5714            0 :                 ereport(ERROR,
    5715              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5716              :                          errmsg("unit \"%s\" not supported for type %s",
    5717              :                                 lowunits, format_type_be(TIMESTAMPOID))));
    5718              :                 intresult = 0;
    5719              :         }
    5720              :     }
    5721              :     else
    5722              :     {
    5723            0 :         ereport(ERROR,
    5724              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5725              :                  errmsg("unit \"%s\" not recognized for type %s",
    5726              :                         lowunits, format_type_be(TIMESTAMPOID))));
    5727              :         intresult = 0;
    5728              :     }
    5729              : 
    5730         3600 :     if (retnumeric)
    5731          189 :         PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    5732              :     else
    5733         3411 :         PG_RETURN_FLOAT8(intresult);
    5734              : }
    5735              : 
    5736              : Datum
    5737         4380 : timestamp_part(PG_FUNCTION_ARGS)
    5738              : {
    5739         4380 :     return timestamp_part_common(fcinfo, false);
    5740              : }
    5741              : 
    5742              : Datum
    5743          981 : extract_timestamp(PG_FUNCTION_ARGS)
    5744              : {
    5745          981 :     return timestamp_part_common(fcinfo, true);
    5746              : }
    5747              : 
    5748              : /* timestamptz_part() and extract_timestamptz()
    5749              :  * Extract specified field from timestamp with time zone.
    5750              :  */
    5751              : static Datum
    5752        18736 : timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
    5753              : {
    5754        18736 :     text       *units = PG_GETARG_TEXT_PP(0);
    5755        18736 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    5756              :     int64       intresult;
    5757              :     Timestamp   epoch;
    5758              :     int         tz;
    5759              :     int         type,
    5760              :                 val;
    5761              :     char       *lowunits;
    5762              :     fsec_t      fsec;
    5763              :     struct pg_tm tt,
    5764        18736 :                *tm = &tt;
    5765              : 
    5766        18736 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    5767        18736 :                                             VARSIZE_ANY_EXHDR(units),
    5768              :                                             false);
    5769              : 
    5770        18736 :     type = DecodeUnits(0, lowunits, &val);
    5771        18736 :     if (type == UNKNOWN_FIELD)
    5772        14962 :         type = DecodeSpecial(0, lowunits, &val);
    5773              : 
    5774        18736 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5775              :     {
    5776          162 :         double      r = NonFiniteTimestampTzPart(type, val, lowunits,
    5777              :                                                  TIMESTAMP_IS_NOBEGIN(timestamp),
    5778              :                                                  true);
    5779              : 
    5780          162 :         if (r != 0.0)
    5781              :         {
    5782           54 :             if (retnumeric)
    5783              :             {
    5784           12 :                 if (r < 0)
    5785            6 :                     return DirectFunctionCall3(numeric_in,
    5786              :                                                CStringGetDatum("-Infinity"),
    5787              :                                                ObjectIdGetDatum(InvalidOid),
    5788              :                                                Int32GetDatum(-1));
    5789            6 :                 else if (r > 0)
    5790            6 :                     return DirectFunctionCall3(numeric_in,
    5791              :                                                CStringGetDatum("Infinity"),
    5792              :                                                ObjectIdGetDatum(InvalidOid),
    5793              :                                                Int32GetDatum(-1));
    5794              :             }
    5795              :             else
    5796           42 :                 PG_RETURN_FLOAT8(r);
    5797              :         }
    5798              :         else
    5799          108 :             PG_RETURN_NULL();
    5800              :     }
    5801              : 
    5802        18574 :     if (type == UNITS)
    5803              :     {
    5804         4842 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    5805            0 :             ereport(ERROR,
    5806              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5807              :                      errmsg("timestamp out of range")));
    5808              : 
    5809         4842 :         switch (val)
    5810              :         {
    5811          192 :             case DTK_TZ:
    5812          192 :                 intresult = -tz;
    5813          192 :                 break;
    5814              : 
    5815          192 :             case DTK_TZ_MINUTE:
    5816          192 :                 intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
    5817          192 :                 break;
    5818              : 
    5819          192 :             case DTK_TZ_HOUR:
    5820          192 :                 intresult = -tz / SECS_PER_HOUR;
    5821          192 :                 break;
    5822              : 
    5823          384 :             case DTK_MICROSEC:
    5824          384 :                 intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
    5825          384 :                 break;
    5826              : 
    5827          384 :             case DTK_MILLISEC:
    5828          384 :                 if (retnumeric)
    5829              :                     /*---
    5830              :                      * tm->tm_sec * 1000 + fsec / 1000
    5831              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1000
    5832              :                      */
    5833          192 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
    5834              :                 else
    5835          192 :                     PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
    5836              :                 break;
    5837              : 
    5838          384 :             case DTK_SECOND:
    5839          384 :                 if (retnumeric)
    5840              :                     /*---
    5841              :                      * tm->tm_sec + fsec / 1'000'000
    5842              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
    5843              :                      */
    5844          192 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
    5845              :                 else
    5846          192 :                     PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
    5847              :                 break;
    5848              : 
    5849          192 :             case DTK_MINUTE:
    5850          192 :                 intresult = tm->tm_min;
    5851          192 :                 break;
    5852              : 
    5853          192 :             case DTK_HOUR:
    5854          192 :                 intresult = tm->tm_hour;
    5855          192 :                 break;
    5856              : 
    5857          192 :             case DTK_DAY:
    5858          192 :                 intresult = tm->tm_mday;
    5859          192 :                 break;
    5860              : 
    5861          192 :             case DTK_MONTH:
    5862          192 :                 intresult = tm->tm_mon;
    5863          192 :                 break;
    5864              : 
    5865          192 :             case DTK_QUARTER:
    5866          192 :                 intresult = (tm->tm_mon - 1) / 3 + 1;
    5867          192 :                 break;
    5868              : 
    5869          192 :             case DTK_WEEK:
    5870          192 :                 intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    5871          192 :                 break;
    5872              : 
    5873          204 :             case DTK_YEAR:
    5874          204 :                 if (tm->tm_year > 0)
    5875          201 :                     intresult = tm->tm_year;
    5876              :                 else
    5877              :                     /* there is no year 0, just 1 BC and 1 AD */
    5878            3 :                     intresult = tm->tm_year - 1;
    5879          204 :                 break;
    5880              : 
    5881          192 :             case DTK_DECADE:
    5882              :                 /* see comments in timestamp_part */
    5883          192 :                 if (tm->tm_year > 0)
    5884          189 :                     intresult = tm->tm_year / 10;
    5885              :                 else
    5886            3 :                     intresult = -((8 - (tm->tm_year - 1)) / 10);
    5887          192 :                 break;
    5888              : 
    5889          192 :             case DTK_CENTURY:
    5890              :                 /* see comments in timestamp_part */
    5891          192 :                 if (tm->tm_year > 0)
    5892          189 :                     intresult = (tm->tm_year + 99) / 100;
    5893              :                 else
    5894            3 :                     intresult = -((99 - (tm->tm_year - 1)) / 100);
    5895          192 :                 break;
    5896              : 
    5897          192 :             case DTK_MILLENNIUM:
    5898              :                 /* see comments in timestamp_part */
    5899          192 :                 if (tm->tm_year > 0)
    5900          189 :                     intresult = (tm->tm_year + 999) / 1000;
    5901              :                 else
    5902            3 :                     intresult = -((999 - (tm->tm_year - 1)) / 1000);
    5903          192 :                 break;
    5904              : 
    5905          384 :             case DTK_JULIAN:
    5906          384 :                 if (retnumeric)
    5907          192 :                     PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
    5908              :                                                        numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
    5909              :                                                                         int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
    5910              :                                                                         NULL),
    5911              :                                                        NULL));
    5912              :                 else
    5913          192 :                     PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
    5914              :                                      ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
    5915              :                                       tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
    5916              :                 break;
    5917              : 
    5918          192 :             case DTK_ISOYEAR:
    5919          192 :                 intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
    5920              :                 /* Adjust BC years */
    5921          192 :                 if (intresult <= 0)
    5922            3 :                     intresult -= 1;
    5923          192 :                 break;
    5924              : 
    5925          414 :             case DTK_DOW:
    5926              :             case DTK_ISODOW:
    5927          414 :                 intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
    5928          414 :                 if (val == DTK_ISODOW && intresult == 0)
    5929            9 :                     intresult = 7;
    5930          414 :                 break;
    5931              : 
    5932          192 :             case DTK_DOY:
    5933          192 :                 intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
    5934          192 :                              - date2j(tm->tm_year, 1, 1) + 1);
    5935          192 :                 break;
    5936              : 
    5937            0 :             default:
    5938            0 :                 ereport(ERROR,
    5939              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5940              :                          errmsg("unit \"%s\" not supported for type %s",
    5941              :                                 lowunits, format_type_be(TIMESTAMPTZOID))));
    5942              :                 intresult = 0;
    5943              :         }
    5944              :     }
    5945        13732 :     else if (type == RESERV)
    5946              :     {
    5947        13732 :         switch (val)
    5948              :         {
    5949        13732 :             case DTK_EPOCH:
    5950        13732 :                 epoch = SetEpochTimestamp();
    5951              :                 /* (timestamp - epoch) / 1000000 */
    5952        13732 :                 if (retnumeric)
    5953              :                 {
    5954              :                     Numeric     result;
    5955              : 
    5956        13537 :                     if (timestamp < (PG_INT64_MAX + epoch))
    5957        13534 :                         result = int64_div_fast_to_numeric(timestamp - epoch, 6);
    5958              :                     else
    5959              :                     {
    5960            3 :                         result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
    5961              :                                                                    int64_to_numeric(epoch),
    5962              :                                                                    NULL),
    5963              :                                                   int64_to_numeric(1000000),
    5964              :                                                   NULL);
    5965            3 :                         result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
    5966              :                                                                      NumericGetDatum(result),
    5967              :                                                                      Int32GetDatum(6)));
    5968              :                     }
    5969        13537 :                     PG_RETURN_NUMERIC(result);
    5970              :                 }
    5971              :                 else
    5972              :                 {
    5973              :                     float8      result;
    5974              : 
    5975              :                     /* try to avoid precision loss in subtraction */
    5976          195 :                     if (timestamp < (PG_INT64_MAX + epoch))
    5977          192 :                         result = (timestamp - epoch) / 1000000.0;
    5978              :                     else
    5979            3 :                         result = ((float8) timestamp - epoch) / 1000000.0;
    5980          195 :                     PG_RETURN_FLOAT8(result);
    5981              :                 }
    5982              :                 break;
    5983              : 
    5984            0 :             default:
    5985            0 :                 ereport(ERROR,
    5986              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5987              :                          errmsg("unit \"%s\" not supported for type %s",
    5988              :                                 lowunits, format_type_be(TIMESTAMPTZOID))));
    5989              :                 intresult = 0;
    5990              :         }
    5991              :     }
    5992              :     else
    5993              :     {
    5994            0 :         ereport(ERROR,
    5995              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5996              :                  errmsg("unit \"%s\" not recognized for type %s",
    5997              :                         lowunits, format_type_be(TIMESTAMPTZOID))));
    5998              : 
    5999              :         intresult = 0;
    6000              :     }
    6001              : 
    6002         3690 :     if (retnumeric)
    6003          234 :         PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    6004              :     else
    6005         3456 :         PG_RETURN_FLOAT8(intresult);
    6006              : }
    6007              : 
    6008              : Datum
    6009         4359 : timestamptz_part(PG_FUNCTION_ARGS)
    6010              : {
    6011         4359 :     return timestamptz_part_common(fcinfo, false);
    6012              : }
    6013              : 
    6014              : Datum
    6015        14377 : extract_timestamptz(PG_FUNCTION_ARGS)
    6016              : {
    6017        14377 :     return timestamptz_part_common(fcinfo, true);
    6018              : }
    6019              : 
    6020              : /*
    6021              :  * NonFiniteIntervalPart
    6022              :  *
    6023              :  *  Used by interval_part when extracting from infinite interval.  Returns
    6024              :  *  +/-Infinity if that is the appropriate result, otherwise returns zero
    6025              :  *  (which should be taken as meaning to return NULL).
    6026              :  *
    6027              :  *  Errors thrown here for invalid units should exactly match those that
    6028              :  *  would be thrown in the calling functions, else there will be unexpected
    6029              :  *  discrepancies between finite- and infinite-input cases.
    6030              :  */
    6031              : static float8
    6032          192 : NonFiniteIntervalPart(int type, int unit, char *lowunits, bool isNegative)
    6033              : {
    6034          192 :     if ((type != UNITS) && (type != RESERV))
    6035            0 :         ereport(ERROR,
    6036              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6037              :                  errmsg("unit \"%s\" not recognized for type %s",
    6038              :                         lowunits, format_type_be(INTERVALOID))));
    6039              : 
    6040          192 :     switch (unit)
    6041              :     {
    6042              :             /* Oscillating units */
    6043          102 :         case DTK_MICROSEC:
    6044              :         case DTK_MILLISEC:
    6045              :         case DTK_SECOND:
    6046              :         case DTK_MINUTE:
    6047              :         case DTK_WEEK:
    6048              :         case DTK_MONTH:
    6049              :         case DTK_QUARTER:
    6050          102 :             return 0.0;
    6051              : 
    6052              :             /* Monotonically-increasing units */
    6053           90 :         case DTK_HOUR:
    6054              :         case DTK_DAY:
    6055              :         case DTK_YEAR:
    6056              :         case DTK_DECADE:
    6057              :         case DTK_CENTURY:
    6058              :         case DTK_MILLENNIUM:
    6059              :         case DTK_EPOCH:
    6060           90 :             if (isNegative)
    6061           45 :                 return -get_float8_infinity();
    6062              :             else
    6063           45 :                 return get_float8_infinity();
    6064              : 
    6065            0 :         default:
    6066            0 :             ereport(ERROR,
    6067              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6068              :                      errmsg("unit \"%s\" not supported for type %s",
    6069              :                             lowunits, format_type_be(INTERVALOID))));
    6070              :             return 0.0;         /* keep compiler quiet */
    6071              :     }
    6072              : }
    6073              : 
    6074              : /* interval_part() and extract_interval()
    6075              :  * Extract specified field from interval.
    6076              :  */
    6077              : static Datum
    6078         1188 : interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
    6079              : {
    6080         1188 :     text       *units = PG_GETARG_TEXT_PP(0);
    6081         1188 :     Interval   *interval = PG_GETARG_INTERVAL_P(1);
    6082              :     int64       intresult;
    6083              :     int         type,
    6084              :                 val;
    6085              :     char       *lowunits;
    6086              :     struct pg_itm tt,
    6087         1188 :                *tm = &tt;
    6088              : 
    6089         1188 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    6090         1188 :                                             VARSIZE_ANY_EXHDR(units),
    6091              :                                             false);
    6092              : 
    6093         1188 :     type = DecodeUnits(0, lowunits, &val);
    6094         1188 :     if (type == UNKNOWN_FIELD)
    6095          117 :         type = DecodeSpecial(0, lowunits, &val);
    6096              : 
    6097         1188 :     if (INTERVAL_NOT_FINITE(interval))
    6098              :     {
    6099          192 :         double      r = NonFiniteIntervalPart(type, val, lowunits,
    6100          192 :                                               INTERVAL_IS_NOBEGIN(interval));
    6101              : 
    6102          192 :         if (r != 0.0)
    6103              :         {
    6104           90 :             if (retnumeric)
    6105              :             {
    6106           84 :                 if (r < 0)
    6107           42 :                     return DirectFunctionCall3(numeric_in,
    6108              :                                                CStringGetDatum("-Infinity"),
    6109              :                                                ObjectIdGetDatum(InvalidOid),
    6110              :                                                Int32GetDatum(-1));
    6111           42 :                 else if (r > 0)
    6112           42 :                     return DirectFunctionCall3(numeric_in,
    6113              :                                                CStringGetDatum("Infinity"),
    6114              :                                                ObjectIdGetDatum(InvalidOid),
    6115              :                                                Int32GetDatum(-1));
    6116              :             }
    6117              :             else
    6118            6 :                 PG_RETURN_FLOAT8(r);
    6119              :         }
    6120              :         else
    6121          102 :             PG_RETURN_NULL();
    6122              :     }
    6123              : 
    6124          996 :     if (type == UNITS)
    6125              :     {
    6126          897 :         interval2itm(*interval, tm);
    6127          897 :         switch (val)
    6128              :         {
    6129           90 :             case DTK_MICROSEC:
    6130           90 :                 intresult = tm->tm_sec * INT64CONST(1000000) + tm->tm_usec;
    6131           90 :                 break;
    6132              : 
    6133           90 :             case DTK_MILLISEC:
    6134           90 :                 if (retnumeric)
    6135              :                     /*---
    6136              :                      * tm->tm_sec * 1000 + fsec / 1000
    6137              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1000
    6138              :                      */
    6139           60 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 3));
    6140              :                 else
    6141           30 :                     PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + tm->tm_usec / 1000.0);
    6142              :                 break;
    6143              : 
    6144           90 :             case DTK_SECOND:
    6145           90 :                 if (retnumeric)
    6146              :                     /*---
    6147              :                      * tm->tm_sec + fsec / 1'000'000
    6148              :                      * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
    6149              :                      */
    6150           60 :                     PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 6));
    6151              :                 else
    6152           30 :                     PG_RETURN_FLOAT8(tm->tm_sec + tm->tm_usec / 1000000.0);
    6153              :                 break;
    6154              : 
    6155           60 :             case DTK_MINUTE:
    6156           60 :                 intresult = tm->tm_min;
    6157           60 :                 break;
    6158              : 
    6159           60 :             case DTK_HOUR:
    6160           60 :                 intresult = tm->tm_hour;
    6161           60 :                 break;
    6162              : 
    6163           60 :             case DTK_DAY:
    6164           60 :                 intresult = tm->tm_mday;
    6165           60 :                 break;
    6166              : 
    6167           60 :             case DTK_WEEK:
    6168           60 :                 intresult = tm->tm_mday / 7;
    6169           60 :                 break;
    6170              : 
    6171           60 :             case DTK_MONTH:
    6172           60 :                 intresult = tm->tm_mon;
    6173           60 :                 break;
    6174              : 
    6175           60 :             case DTK_QUARTER:
    6176              : 
    6177              :                 /*
    6178              :                  * We want to maintain the rule that a field extracted from a
    6179              :                  * negative interval is the negative of the field's value for
    6180              :                  * the sign-reversed interval.  The broken-down tm_year and
    6181              :                  * tm_mon aren't very helpful for that, so work from
    6182              :                  * interval->month.
    6183              :                  */
    6184           60 :                 if (interval->month >= 0)
    6185           45 :                     intresult = (tm->tm_mon / 3) + 1;
    6186              :                 else
    6187           15 :                     intresult = -(((-interval->month % MONTHS_PER_YEAR) / 3) + 1);
    6188           60 :                 break;
    6189              : 
    6190           60 :             case DTK_YEAR:
    6191           60 :                 intresult = tm->tm_year;
    6192           60 :                 break;
    6193              : 
    6194           72 :             case DTK_DECADE:
    6195              :                 /* caution: C division may have negative remainder */
    6196           72 :                 intresult = tm->tm_year / 10;
    6197           72 :                 break;
    6198              : 
    6199           72 :             case DTK_CENTURY:
    6200              :                 /* caution: C division may have negative remainder */
    6201           72 :                 intresult = tm->tm_year / 100;
    6202           72 :                 break;
    6203              : 
    6204           60 :             case DTK_MILLENNIUM:
    6205              :                 /* caution: C division may have negative remainder */
    6206           60 :                 intresult = tm->tm_year / 1000;
    6207           60 :                 break;
    6208              : 
    6209            3 :             default:
    6210            3 :                 ereport(ERROR,
    6211              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6212              :                          errmsg("unit \"%s\" not supported for type %s",
    6213              :                                 lowunits, format_type_be(INTERVALOID))));
    6214              :                 intresult = 0;
    6215              :         }
    6216              :     }
    6217           99 :     else if (type == RESERV && val == DTK_EPOCH)
    6218              :     {
    6219           96 :         if (retnumeric)
    6220              :         {
    6221              :             Numeric     result;
    6222              :             int64       secs_from_day_month;
    6223              :             int64       val;
    6224              : 
    6225              :             /*
    6226              :              * To do this calculation in integer arithmetic even though
    6227              :              * DAYS_PER_YEAR is fractional, multiply everything by 4 and then
    6228              :              * divide by 4 again at the end.  This relies on DAYS_PER_YEAR
    6229              :              * being a multiple of 0.25 and on SECS_PER_DAY being a multiple
    6230              :              * of 4.
    6231              :              */
    6232           66 :             secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) +
    6233           66 :                                    (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) +
    6234           66 :                                    (int64) 4 * interval->day) * (SECS_PER_DAY / 4);
    6235              : 
    6236              :             /*---
    6237              :              * result = secs_from_day_month + interval->time / 1'000'000
    6238              :              * = (secs_from_day_month * 1'000'000 + interval->time) / 1'000'000
    6239              :              */
    6240              : 
    6241              :             /*
    6242              :              * Try the computation inside int64; if it overflows, do it in
    6243              :              * numeric (slower).  This overflow happens around 10^9 days, so
    6244              :              * not common in practice.
    6245              :              */
    6246           66 :             if (!pg_mul_s64_overflow(secs_from_day_month, 1000000, &val) &&
    6247           63 :                 !pg_add_s64_overflow(val, interval->time, &val))
    6248           63 :                 result = int64_div_fast_to_numeric(val, 6);
    6249              :             else
    6250              :                 result =
    6251            3 :                     numeric_add_safe(int64_div_fast_to_numeric(interval->time, 6),
    6252              :                                      int64_to_numeric(secs_from_day_month),
    6253              :                                      NULL);
    6254              : 
    6255           66 :             PG_RETURN_NUMERIC(result);
    6256              :         }
    6257              :         else
    6258              :         {
    6259              :             float8      result;
    6260              : 
    6261           30 :             result = interval->time / 1000000.0;
    6262           30 :             result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
    6263           30 :             result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
    6264           30 :             result += ((double) SECS_PER_DAY) * interval->day;
    6265              : 
    6266           30 :             PG_RETURN_FLOAT8(result);
    6267              :         }
    6268              :     }
    6269              :     else
    6270              :     {
    6271            3 :         ereport(ERROR,
    6272              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6273              :                  errmsg("unit \"%s\" not recognized for type %s",
    6274              :                         lowunits, format_type_be(INTERVALOID))));
    6275              :         intresult = 0;
    6276              :     }
    6277              : 
    6278          714 :     if (retnumeric)
    6279          684 :         PG_RETURN_NUMERIC(int64_to_numeric(intresult));
    6280              :     else
    6281           30 :         PG_RETURN_FLOAT8(intresult);
    6282              : }
    6283              : 
    6284              : Datum
    6285          144 : interval_part(PG_FUNCTION_ARGS)
    6286              : {
    6287          144 :     return interval_part_common(fcinfo, false);
    6288              : }
    6289              : 
    6290              : Datum
    6291         1044 : extract_interval(PG_FUNCTION_ARGS)
    6292              : {
    6293         1044 :     return interval_part_common(fcinfo, true);
    6294              : }
    6295              : 
    6296              : 
    6297              : /*  timestamp_zone()
    6298              :  *  Encode timestamp type with specified time zone.
    6299              :  *  This function is just timestamp2timestamptz() except instead of
    6300              :  *  shifting to the global timezone, we shift to the specified timezone.
    6301              :  *  This is different from the other AT TIME ZONE cases because instead
    6302              :  *  of shifting _to_ a new time zone, it sets the time to _be_ the
    6303              :  *  specified timezone.
    6304              :  */
    6305              : Datum
    6306           84 : timestamp_zone(PG_FUNCTION_ARGS)
    6307              : {
    6308           84 :     text       *zone = PG_GETARG_TEXT_PP(0);
    6309           84 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    6310              :     TimestampTz result;
    6311              :     int         tz;
    6312              :     char        tzname[TZ_STRLEN_MAX + 1];
    6313              :     int         type,
    6314              :                 val;
    6315              :     pg_tz      *tzp;
    6316              :     struct pg_tm tm;
    6317              :     fsec_t      fsec;
    6318              : 
    6319           84 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6320            0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    6321              : 
    6322              :     /*
    6323              :      * Look up the requested timezone.
    6324              :      */
    6325           84 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    6326              : 
    6327           84 :     type = DecodeTimezoneName(tzname, &val, &tzp);
    6328              : 
    6329           84 :     if (type == TZNAME_FIXED_OFFSET)
    6330              :     {
    6331              :         /* fixed-offset abbreviation */
    6332            0 :         tz = val;
    6333            0 :         result = dt2local(timestamp, tz);
    6334              :     }
    6335           84 :     else if (type == TZNAME_DYNTZ)
    6336              :     {
    6337              :         /* dynamic-offset abbreviation, resolve using specified time */
    6338           42 :         if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
    6339            0 :             ereport(ERROR,
    6340              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6341              :                      errmsg("timestamp out of range")));
    6342           42 :         tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
    6343           42 :         result = dt2local(timestamp, tz);
    6344              :     }
    6345              :     else
    6346              :     {
    6347              :         /* full zone name, rotate to that zone */
    6348           42 :         if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
    6349            0 :             ereport(ERROR,
    6350              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6351              :                      errmsg("timestamp out of range")));
    6352           42 :         tz = DetermineTimeZoneOffset(&tm, tzp);
    6353           42 :         if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
    6354            0 :             ereport(ERROR,
    6355              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6356              :                      errmsg("timestamp out of range")));
    6357              :     }
    6358              : 
    6359           84 :     if (!IS_VALID_TIMESTAMP(result))
    6360            0 :         ereport(ERROR,
    6361              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6362              :                  errmsg("timestamp out of range")));
    6363              : 
    6364           84 :     PG_RETURN_TIMESTAMPTZ(result);
    6365              : }
    6366              : 
    6367              : /* timestamp_izone()
    6368              :  * Encode timestamp type with specified time interval as time zone.
    6369              :  */
    6370              : Datum
    6371            6 : timestamp_izone(PG_FUNCTION_ARGS)
    6372              : {
    6373            6 :     Interval   *zone = PG_GETARG_INTERVAL_P(0);
    6374            6 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    6375              :     TimestampTz result;
    6376              :     int         tz;
    6377              : 
    6378            6 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6379            0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    6380              : 
    6381            6 :     if (INTERVAL_NOT_FINITE(zone))
    6382            6 :         ereport(ERROR,
    6383              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6384              :                  errmsg("interval time zone \"%s\" must be finite",
    6385              :                         DatumGetCString(DirectFunctionCall1(interval_out,
    6386              :                                                             PointerGetDatum(zone))))));
    6387              : 
    6388            0 :     if (zone->month != 0 || zone->day != 0)
    6389            0 :         ereport(ERROR,
    6390              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6391              :                  errmsg("interval time zone \"%s\" must not include months or days",
    6392              :                         DatumGetCString(DirectFunctionCall1(interval_out,
    6393              :                                                             PointerGetDatum(zone))))));
    6394              : 
    6395            0 :     tz = zone->time / USECS_PER_SEC;
    6396              : 
    6397            0 :     result = dt2local(timestamp, tz);
    6398              : 
    6399            0 :     if (!IS_VALID_TIMESTAMP(result))
    6400            0 :         ereport(ERROR,
    6401              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6402              :                  errmsg("timestamp out of range")));
    6403              : 
    6404            0 :     PG_RETURN_TIMESTAMPTZ(result);
    6405              : }                               /* timestamp_izone() */
    6406              : 
    6407              : /* TimestampTimestampTzRequiresRewrite()
    6408              :  *
    6409              :  * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
    6410              :  * timestamptz_timestamp to be no-ops, where the return value has the same
    6411              :  * bits as the argument.  Since project convention is to assume a GUC changes
    6412              :  * no more often than STABLE functions change, the answer is valid that long.
    6413              :  */
    6414              : bool
    6415            9 : TimestampTimestampTzRequiresRewrite(void)
    6416              : {
    6417              :     long        offset;
    6418              : 
    6419            9 :     if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
    6420            6 :         return false;
    6421            3 :     return true;
    6422              : }
    6423              : 
    6424              : /* timestamp_timestamptz()
    6425              :  * Convert local timestamp to timestamp at GMT
    6426              :  */
    6427              : Datum
    6428          111 : timestamp_timestamptz(PG_FUNCTION_ARGS)
    6429              : {
    6430          111 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    6431              : 
    6432          111 :     PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
    6433              : }
    6434              : 
    6435              : /*
    6436              :  * Convert timestamp to timestamp with time zone.
    6437              :  *
    6438              :  * If the timestamp is finite but out of the valid range for timestamptz,
    6439              :  * error handling proceeds based on escontext.
    6440              :  *
    6441              :  * If escontext is NULL, we throw an out-of-range error (hard error).
    6442              :  * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
    6443              :  * upper bound overflow, respectively, and record a soft error.
    6444              :  */
    6445              : TimestampTz
    6446         8160 : timestamp2timestamptz_safe(Timestamp timestamp, Node *escontext)
    6447              : {
    6448              :     TimestampTz result;
    6449              :     struct pg_tm tt,
    6450         8160 :                *tm = &tt;
    6451              :     fsec_t      fsec;
    6452              :     int         tz;
    6453              : 
    6454         8160 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6455           17 :         return timestamp;
    6456              : 
    6457              :     /* timestamp2tm should not fail on valid timestamps, but cope */
    6458         8143 :     if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
    6459              :     {
    6460         8143 :         tz = DetermineTimeZoneOffset(tm, session_timezone);
    6461              : 
    6462         8143 :         result = dt2local(timestamp, -tz);
    6463              : 
    6464         8143 :         if (IS_VALID_TIMESTAMP(result))
    6465         8137 :             return result;
    6466              :     }
    6467              : 
    6468            6 :     if (timestamp < 0)
    6469            6 :         TIMESTAMP_NOBEGIN(result);
    6470              :     else
    6471            0 :         TIMESTAMP_NOEND(result);
    6472              : 
    6473            6 :     ereturn(escontext, result,
    6474              :             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6475              :              errmsg("timestamp out of range")));
    6476              : }
    6477              : 
    6478              : /*
    6479              :  * Promote timestamp to timestamptz, throwing error for overflow.
    6480              :  */
    6481              : static TimestampTz
    6482          117 : timestamp2timestamptz(Timestamp timestamp)
    6483              : {
    6484          117 :     return timestamp2timestamptz_safe(timestamp, NULL);
    6485              : }
    6486              : 
    6487              : /* timestamptz_timestamp()
    6488              :  * Convert timestamp at GMT to local timestamp
    6489              :  */
    6490              : Datum
    6491        31086 : timestamptz_timestamp(PG_FUNCTION_ARGS)
    6492              : {
    6493        31086 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    6494              : 
    6495        31086 :     PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
    6496              : }
    6497              : 
    6498              : /*
    6499              :  * Convert timestamptz to timestamp, throwing error for overflow.
    6500              :  */
    6501              : static Timestamp
    6502        31119 : timestamptz2timestamp(TimestampTz timestamp)
    6503              : {
    6504        31119 :     return timestamptz2timestamp_safe(timestamp, NULL);
    6505              : }
    6506              : 
    6507              : /*
    6508              :  * Convert timestamp with time zone to timestamp.
    6509              :  *
    6510              :  * If the timestamptz is finite but out of the valid range for timestamp,
    6511              :  * error handling proceeds based on escontext.
    6512              :  *
    6513              :  * If escontext is NULL, we throw an out-of-range error (hard error).
    6514              :  * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
    6515              :  * upper bound overflow, respectively, and record a soft error.
    6516              :  */
    6517              : Timestamp
    6518        31139 : timestamptz2timestamp_safe(TimestampTz timestamp, Node *escontext)
    6519              : {
    6520              :     Timestamp   result;
    6521              :     struct pg_tm tt,
    6522        31139 :                *tm = &tt;
    6523              :     fsec_t      fsec;
    6524              :     int         tz;
    6525              : 
    6526        31139 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6527           12 :         result = timestamp;
    6528              :     else
    6529              :     {
    6530        31127 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    6531              :         {
    6532            0 :             if (timestamp < 0)
    6533            0 :                 TIMESTAMP_NOBEGIN(result);
    6534              :             else
    6535            0 :                 TIMESTAMP_NOEND(result);
    6536              : 
    6537            0 :             ereturn(escontext, result,
    6538              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6539              :                      errmsg("timestamp out of range")));
    6540              :         }
    6541        31127 :         if (tm2timestamp(tm, fsec, NULL, &result) != 0)
    6542              :         {
    6543            2 :             if (timestamp < 0)
    6544            2 :                 TIMESTAMP_NOBEGIN(result);
    6545              :             else
    6546            0 :                 TIMESTAMP_NOEND(result);
    6547              : 
    6548            2 :             ereturn(escontext, result,
    6549              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6550              :                      errmsg("timestamp out of range")));
    6551              :         }
    6552              :     }
    6553        31137 :     return result;
    6554              : }
    6555              : 
    6556              : /* timestamptz_zone()
    6557              :  * Evaluate timestamp with time zone type at the specified time zone.
    6558              :  * Returns a timestamp without time zone.
    6559              :  */
    6560              : Datum
    6561          117 : timestamptz_zone(PG_FUNCTION_ARGS)
    6562              : {
    6563          117 :     text       *zone = PG_GETARG_TEXT_PP(0);
    6564          117 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    6565              :     Timestamp   result;
    6566              :     int         tz;
    6567              :     char        tzname[TZ_STRLEN_MAX + 1];
    6568              :     int         type,
    6569              :                 val;
    6570              :     pg_tz      *tzp;
    6571              : 
    6572          117 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6573           12 :         PG_RETURN_TIMESTAMP(timestamp);
    6574              : 
    6575              :     /*
    6576              :      * Look up the requested timezone.
    6577              :      */
    6578          105 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    6579              : 
    6580          105 :     type = DecodeTimezoneName(tzname, &val, &tzp);
    6581              : 
    6582          102 :     if (type == TZNAME_FIXED_OFFSET)
    6583              :     {
    6584              :         /* fixed-offset abbreviation */
    6585           24 :         tz = -val;
    6586           24 :         result = dt2local(timestamp, tz);
    6587              :     }
    6588           78 :     else if (type == TZNAME_DYNTZ)
    6589              :     {
    6590              :         /* dynamic-offset abbreviation, resolve using specified time */
    6591              :         int         isdst;
    6592              : 
    6593           36 :         tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
    6594           36 :         result = dt2local(timestamp, tz);
    6595              :     }
    6596              :     else
    6597              :     {
    6598              :         /* full zone name, rotate from that zone */
    6599              :         struct pg_tm tm;
    6600              :         fsec_t      fsec;
    6601              : 
    6602           42 :         if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
    6603            0 :             ereport(ERROR,
    6604              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6605              :                      errmsg("timestamp out of range")));
    6606           42 :         if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
    6607            0 :             ereport(ERROR,
    6608              :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6609              :                      errmsg("timestamp out of range")));
    6610              :     }
    6611              : 
    6612          102 :     if (!IS_VALID_TIMESTAMP(result))
    6613            0 :         ereport(ERROR,
    6614              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6615              :                  errmsg("timestamp out of range")));
    6616              : 
    6617          102 :     PG_RETURN_TIMESTAMP(result);
    6618              : }
    6619              : 
    6620              : /* timestamptz_izone()
    6621              :  * Encode timestamp with time zone type with specified time interval as time zone.
    6622              :  * Returns a timestamp without time zone.
    6623              :  */
    6624              : Datum
    6625            6 : timestamptz_izone(PG_FUNCTION_ARGS)
    6626              : {
    6627            6 :     Interval   *zone = PG_GETARG_INTERVAL_P(0);
    6628            6 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    6629              :     Timestamp   result;
    6630              :     int         tz;
    6631              : 
    6632            6 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    6633            0 :         PG_RETURN_TIMESTAMP(timestamp);
    6634              : 
    6635            6 :     if (INTERVAL_NOT_FINITE(zone))
    6636            6 :         ereport(ERROR,
    6637              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6638              :                  errmsg("interval time zone \"%s\" must be finite",
    6639              :                         DatumGetCString(DirectFunctionCall1(interval_out,
    6640              :                                                             PointerGetDatum(zone))))));
    6641              : 
    6642            0 :     if (zone->month != 0 || zone->day != 0)
    6643            0 :         ereport(ERROR,
    6644              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6645              :                  errmsg("interval time zone \"%s\" must not include months or days",
    6646              :                         DatumGetCString(DirectFunctionCall1(interval_out,
    6647              :                                                             PointerGetDatum(zone))))));
    6648              : 
    6649            0 :     tz = -(zone->time / USECS_PER_SEC);
    6650              : 
    6651            0 :     result = dt2local(timestamp, tz);
    6652              : 
    6653            0 :     if (!IS_VALID_TIMESTAMP(result))
    6654            0 :         ereport(ERROR,
    6655              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    6656              :                  errmsg("timestamp out of range")));
    6657              : 
    6658            0 :     PG_RETURN_TIMESTAMP(result);
    6659              : }
    6660              : 
    6661              : /* generate_series_timestamp()
    6662              :  * Generate the set of timestamps from start to finish by step
    6663              :  */
    6664              : Datum
    6665          432 : generate_series_timestamp(PG_FUNCTION_ARGS)
    6666              : {
    6667              :     FuncCallContext *funcctx;
    6668              :     generate_series_timestamp_fctx *fctx;
    6669              :     Timestamp   result;
    6670              : 
    6671              :     /* stuff done only on the first call of the function */
    6672          432 :     if (SRF_IS_FIRSTCALL())
    6673              :     {
    6674           22 :         Timestamp   start = PG_GETARG_TIMESTAMP(0);
    6675           22 :         Timestamp   finish = PG_GETARG_TIMESTAMP(1);
    6676           22 :         Interval   *step = PG_GETARG_INTERVAL_P(2);
    6677              :         MemoryContext oldcontext;
    6678              : 
    6679              :         /* create a function context for cross-call persistence */
    6680           22 :         funcctx = SRF_FIRSTCALL_INIT();
    6681              : 
    6682              :         /*
    6683              :          * switch to memory context appropriate for multiple function calls
    6684              :          */
    6685           22 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    6686              : 
    6687              :         /* allocate memory for user context */
    6688           22 :         fctx = palloc_object(generate_series_timestamp_fctx);
    6689              : 
    6690              :         /*
    6691              :          * Use fctx to keep state from call to call. Seed current with the
    6692              :          * original start value
    6693              :          */
    6694           22 :         fctx->current = start;
    6695           22 :         fctx->finish = finish;
    6696           22 :         fctx->step = *step;
    6697              : 
    6698              :         /* Determine sign of the interval */
    6699           22 :         fctx->step_sign = interval_sign(&fctx->step);
    6700              : 
    6701           22 :         if (fctx->step_sign == 0)
    6702            3 :             ereport(ERROR,
    6703              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6704              :                      errmsg("step size cannot equal zero")));
    6705              : 
    6706           19 :         if (INTERVAL_NOT_FINITE((&fctx->step)))
    6707            6 :             ereport(ERROR,
    6708              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6709              :                      errmsg("step size cannot be infinite")));
    6710              : 
    6711           13 :         funcctx->user_fctx = fctx;
    6712           13 :         MemoryContextSwitchTo(oldcontext);
    6713              :     }
    6714              : 
    6715              :     /* stuff done on every call of the function */
    6716          423 :     funcctx = SRF_PERCALL_SETUP();
    6717              : 
    6718              :     /*
    6719              :      * get the saved state and use current as the result for this iteration
    6720              :      */
    6721          423 :     fctx = funcctx->user_fctx;
    6722          423 :     result = fctx->current;
    6723              : 
    6724          846 :     if (fctx->step_sign > 0 ?
    6725          423 :         timestamp_cmp_internal(result, fctx->finish) <= 0 :
    6726            0 :         timestamp_cmp_internal(result, fctx->finish) >= 0)
    6727              :     {
    6728              :         /* increment current in preparation for next iteration */
    6729          413 :         fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
    6730              :                                                               TimestampGetDatum(fctx->current),
    6731              :                                                               PointerGetDatum(&fctx->step)));
    6732              : 
    6733              :         /* do when there is more left to send */
    6734          413 :         SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
    6735              :     }
    6736              :     else
    6737              :     {
    6738              :         /* do when there is no more left */
    6739           10 :         SRF_RETURN_DONE(funcctx);
    6740              :     }
    6741              : }
    6742              : 
    6743              : /* generate_series_timestamptz()
    6744              :  * Generate the set of timestamps from start to finish by step,
    6745              :  * doing arithmetic in the specified or session timezone.
    6746              :  */
    6747              : static Datum
    6748        31341 : generate_series_timestamptz_internal(FunctionCallInfo fcinfo)
    6749              : {
    6750              :     FuncCallContext *funcctx;
    6751              :     generate_series_timestamptz_fctx *fctx;
    6752              :     TimestampTz result;
    6753              : 
    6754              :     /* stuff done only on the first call of the function */
    6755        31341 :     if (SRF_IS_FIRSTCALL())
    6756              :     {
    6757           46 :         TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
    6758           46 :         TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
    6759           46 :         Interval   *step = PG_GETARG_INTERVAL_P(2);
    6760           46 :         text       *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
    6761              :         MemoryContext oldcontext;
    6762              : 
    6763              :         /* create a function context for cross-call persistence */
    6764           46 :         funcctx = SRF_FIRSTCALL_INIT();
    6765              : 
    6766              :         /*
    6767              :          * switch to memory context appropriate for multiple function calls
    6768              :          */
    6769           46 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    6770              : 
    6771              :         /* allocate memory for user context */
    6772           46 :         fctx = palloc_object(generate_series_timestamptz_fctx);
    6773              : 
    6774              :         /*
    6775              :          * Use fctx to keep state from call to call. Seed current with the
    6776              :          * original start value
    6777              :          */
    6778           46 :         fctx->current = start;
    6779           46 :         fctx->finish = finish;
    6780           46 :         fctx->step = *step;
    6781           46 :         fctx->attimezone = zone ? lookup_timezone(zone) : session_timezone;
    6782              : 
    6783              :         /* Determine sign of the interval */
    6784           46 :         fctx->step_sign = interval_sign(&fctx->step);
    6785              : 
    6786           46 :         if (fctx->step_sign == 0)
    6787            6 :             ereport(ERROR,
    6788              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6789              :                      errmsg("step size cannot equal zero")));
    6790              : 
    6791           40 :         if (INTERVAL_NOT_FINITE((&fctx->step)))
    6792            6 :             ereport(ERROR,
    6793              :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6794              :                      errmsg("step size cannot be infinite")));
    6795              : 
    6796           34 :         funcctx->user_fctx = fctx;
    6797           34 :         MemoryContextSwitchTo(oldcontext);
    6798              :     }
    6799              : 
    6800              :     /* stuff done on every call of the function */
    6801        31329 :     funcctx = SRF_PERCALL_SETUP();
    6802              : 
    6803              :     /*
    6804              :      * get the saved state and use current as the result for this iteration
    6805              :      */
    6806        31329 :     fctx = funcctx->user_fctx;
    6807        31329 :     result = fctx->current;
    6808              : 
    6809        62658 :     if (fctx->step_sign > 0 ?
    6810        31194 :         timestamp_cmp_internal(result, fctx->finish) <= 0 :
    6811          135 :         timestamp_cmp_internal(result, fctx->finish) >= 0)
    6812              :     {
    6813              :         /* increment current in preparation for next iteration */
    6814        31298 :         fctx->current = timestamptz_pl_interval_internal(fctx->current,
    6815              :                                                          &fctx->step,
    6816              :                                                          fctx->attimezone);
    6817              : 
    6818              :         /* do when there is more left to send */
    6819        31298 :         SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
    6820              :     }
    6821              :     else
    6822              :     {
    6823              :         /* do when there is no more left */
    6824           31 :         SRF_RETURN_DONE(funcctx);
    6825              :     }
    6826              : }
    6827              : 
    6828              : Datum
    6829        31206 : generate_series_timestamptz(PG_FUNCTION_ARGS)
    6830              : {
    6831        31206 :     return generate_series_timestamptz_internal(fcinfo);
    6832              : }
    6833              : 
    6834              : Datum
    6835          135 : generate_series_timestamptz_at_zone(PG_FUNCTION_ARGS)
    6836              : {
    6837          135 :     return generate_series_timestamptz_internal(fcinfo);
    6838              : }
    6839              : 
    6840              : /*
    6841              :  * Planner support function for generate_series(timestamp, timestamp, interval)
    6842              :  */
    6843              : Datum
    6844          250 : generate_series_timestamp_support(PG_FUNCTION_ARGS)
    6845              : {
    6846          250 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
    6847          250 :     Node       *ret = NULL;
    6848              : 
    6849          250 :     if (IsA(rawreq, SupportRequestRows))
    6850              :     {
    6851              :         /* Try to estimate the number of rows returned */
    6852           67 :         SupportRequestRows *req = (SupportRequestRows *) rawreq;
    6853              : 
    6854           67 :         if (is_funcclause(req->node))    /* be paranoid */
    6855              :         {
    6856           67 :             List       *args = ((FuncExpr *) req->node)->args;
    6857              :             Node       *arg1,
    6858              :                        *arg2,
    6859              :                        *arg3;
    6860              : 
    6861              :             /* We can use estimated argument values here */
    6862           67 :             arg1 = estimate_expression_value(req->root, linitial(args));
    6863           67 :             arg2 = estimate_expression_value(req->root, lsecond(args));
    6864           67 :             arg3 = estimate_expression_value(req->root, lthird(args));
    6865              : 
    6866              :             /*
    6867              :              * If any argument is constant NULL, we can safely assume that
    6868              :              * zero rows are returned.  Otherwise, if they're all non-NULL
    6869              :              * constants, we can calculate the number of rows that will be
    6870              :              * returned.
    6871              :              */
    6872           67 :             if ((IsA(arg1, Const) && ((Const *) arg1)->constisnull) ||
    6873           67 :                 (IsA(arg2, Const) && ((Const *) arg2)->constisnull) ||
    6874           67 :                 (IsA(arg3, Const) && ((Const *) arg3)->constisnull))
    6875              :             {
    6876            0 :                 req->rows = 0;
    6877            0 :                 ret = (Node *) req;
    6878              :             }
    6879           67 :             else if (IsA(arg1, Const) && IsA(arg2, Const) && IsA(arg3, Const))
    6880              :             {
    6881              :                 Timestamp   start,
    6882              :                             finish;
    6883              :                 Interval   *step;
    6884              :                 Datum       diff;
    6885              :                 double      dstep;
    6886              :                 int64       dummy;
    6887              : 
    6888           66 :                 start = DatumGetTimestamp(((Const *) arg1)->constvalue);
    6889           66 :                 finish = DatumGetTimestamp(((Const *) arg2)->constvalue);
    6890           66 :                 step = DatumGetIntervalP(((Const *) arg3)->constvalue);
    6891              : 
    6892              :                 /*
    6893              :                  * Perform some prechecks which could cause timestamp_mi to
    6894              :                  * raise an ERROR.  It's much better to just return some
    6895              :                  * default estimate than error out in a support function.
    6896              :                  */
    6897           66 :                 if (!TIMESTAMP_NOT_FINITE(start) && !TIMESTAMP_NOT_FINITE(finish) &&
    6898           57 :                     !pg_sub_s64_overflow(finish, start, &dummy))
    6899              :                 {
    6900           57 :                     diff = DirectFunctionCall2(timestamp_mi,
    6901              :                                                TimestampGetDatum(finish),
    6902              :                                                TimestampGetDatum(start));
    6903              : 
    6904              : #define INTERVAL_TO_MICROSECONDS(i) ((((double) (i)->month * DAYS_PER_MONTH + (i)->day)) * USECS_PER_DAY + (i)->time)
    6905              : 
    6906           57 :                     dstep = INTERVAL_TO_MICROSECONDS(step);
    6907              : 
    6908              :                     /* This equation works for either sign of step */
    6909           57 :                     if (dstep != 0.0)
    6910              :                     {
    6911           48 :                         Interval   *idiff = DatumGetIntervalP(diff);
    6912           48 :                         double      ddiff = INTERVAL_TO_MICROSECONDS(idiff);
    6913              : 
    6914           48 :                         req->rows = floor(ddiff / dstep + 1.0);
    6915           48 :                         ret = (Node *) req;
    6916              :                     }
    6917              : #undef INTERVAL_TO_MICROSECONDS
    6918              :                 }
    6919              :             }
    6920              :         }
    6921              :     }
    6922              : 
    6923          250 :     PG_RETURN_POINTER(ret);
    6924              : }
    6925              : 
    6926              : 
    6927              : /* timestamp_at_local()
    6928              :  * timestamptz_at_local()
    6929              :  *
    6930              :  * The regression tests do not like two functions with the same proargs and
    6931              :  * prosrc but different proname, but the grammar for AT LOCAL needs an
    6932              :  * overloaded name to handle both types of timestamp, so we make simple
    6933              :  * wrappers for it.
    6934              :  */
    6935              : Datum
    6936           12 : timestamp_at_local(PG_FUNCTION_ARGS)
    6937              : {
    6938           12 :     return timestamp_timestamptz(fcinfo);
    6939              : }
    6940              : 
    6941              : Datum
    6942           12 : timestamptz_at_local(PG_FUNCTION_ARGS)
    6943              : {
    6944           12 :     return timestamptz_timestamp(fcinfo);
    6945              : }
        

Generated by: LCOV version 2.0-1