LCOV - code coverage report
Current view: top level - src/backend/utils/adt - timestamp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 1296 1974 65.7 %
Date: 2019-06-19 16:07:09 Functions: 123 153 80.4 %
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-2019, 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/int128.h"
      26             : #include "funcapi.h"
      27             : #include "libpq/pqformat.h"
      28             : #include "miscadmin.h"
      29             : #include "nodes/makefuncs.h"
      30             : #include "nodes/nodeFuncs.h"
      31             : #include "nodes/supportnodes.h"
      32             : #include "parser/scansup.h"
      33             : #include "utils/array.h"
      34             : #include "utils/builtins.h"
      35             : #include "utils/datetime.h"
      36             : #include "utils/float.h"
      37             : 
      38             : /*
      39             :  * gcc's -ffast-math switch breaks routines that expect exact results from
      40             :  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
      41             :  */
      42             : #ifdef __FAST_MATH__
      43             : #error -ffast-math is known to break this code
      44             : #endif
      45             : 
      46             : #define SAMESIGN(a,b)   (((a) < 0) == ((b) < 0))
      47             : 
      48             : /* Set at postmaster start */
      49             : TimestampTz PgStartTime;
      50             : 
      51             : /* Set at configuration reload */
      52             : TimestampTz PgReloadTime;
      53             : 
      54             : typedef struct
      55             : {
      56             :     Timestamp   current;
      57             :     Timestamp   finish;
      58             :     Interval    step;
      59             :     int         step_sign;
      60             : } generate_series_timestamp_fctx;
      61             : 
      62             : typedef struct
      63             : {
      64             :     TimestampTz current;
      65             :     TimestampTz finish;
      66             :     Interval    step;
      67             :     int         step_sign;
      68             : } generate_series_timestamptz_fctx;
      69             : 
      70             : 
      71             : static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
      72             : static Timestamp dt2local(Timestamp dt, int timezone);
      73             : static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
      74             : static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
      75             : static TimestampTz timestamp2timestamptz(Timestamp timestamp);
      76             : static Timestamp timestamptz2timestamp(TimestampTz timestamp);
      77             : 
      78             : 
      79             : /* common code for timestamptypmodin and timestamptztypmodin */
      80             : static int32
      81         362 : anytimestamp_typmodin(bool istz, ArrayType *ta)
      82             : {
      83             :     int32      *tl;
      84             :     int         n;
      85             : 
      86         362 :     tl = ArrayGetIntegerTypmods(ta, &n);
      87             : 
      88             :     /*
      89             :      * we're not too tense about good error message here because grammar
      90             :      * shouldn't allow wrong number of modifiers for TIMESTAMP
      91             :      */
      92         362 :     if (n != 1)
      93           0 :         ereport(ERROR,
      94             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
      95             :                  errmsg("invalid type modifier")));
      96             : 
      97         362 :     return anytimestamp_typmod_check(istz, tl[0]);
      98             : }
      99             : 
     100             : /* exported so parse_expr.c can use it */
     101             : int32
     102         688 : anytimestamp_typmod_check(bool istz, int32 typmod)
     103             : {
     104         688 :     if (typmod < 0)
     105           0 :         ereport(ERROR,
     106             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     107             :                  errmsg("TIMESTAMP(%d)%s precision must not be negative",
     108             :                         typmod, (istz ? " WITH TIME ZONE" : ""))));
     109         688 :     if (typmod > MAX_TIMESTAMP_PRECISION)
     110             :     {
     111           0 :         ereport(WARNING,
     112             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     113             :                  errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
     114             :                         typmod, (istz ? " WITH TIME ZONE" : ""),
     115             :                         MAX_TIMESTAMP_PRECISION)));
     116           0 :         typmod = MAX_TIMESTAMP_PRECISION;
     117             :     }
     118             : 
     119         688 :     return typmod;
     120             : }
     121             : 
     122             : /* common code for timestamptypmodout and timestamptztypmodout */
     123             : static char *
     124          12 : anytimestamp_typmodout(bool istz, int32 typmod)
     125             : {
     126          12 :     const char *tz = istz ? " with time zone" : " without time zone";
     127             : 
     128          12 :     if (typmod >= 0)
     129          12 :         return psprintf("(%d)%s", (int) typmod, tz);
     130             :     else
     131           0 :         return psprintf("%s", tz);
     132             : }
     133             : 
     134             : 
     135             : /*****************************************************************************
     136             :  *   USER I/O ROUTINES                                                       *
     137             :  *****************************************************************************/
     138             : 
     139             : /* timestamp_in()
     140             :  * Convert a string to internal form.
     141             :  */
     142             : Datum
     143       17226 : timestamp_in(PG_FUNCTION_ARGS)
     144             : {
     145       17226 :     char       *str = PG_GETARG_CSTRING(0);
     146             : 
     147             : #ifdef NOT_USED
     148             :     Oid         typelem = PG_GETARG_OID(1);
     149             : #endif
     150       17226 :     int32       typmod = PG_GETARG_INT32(2);
     151             :     Timestamp   result;
     152             :     fsec_t      fsec;
     153             :     struct pg_tm tt,
     154       17226 :                *tm = &tt;
     155             :     int         tz;
     156             :     int         dtype;
     157             :     int         nf;
     158             :     int         dterr;
     159             :     char       *field[MAXDATEFIELDS];
     160             :     int         ftype[MAXDATEFIELDS];
     161             :     char        workbuf[MAXDATELEN + MAXDATEFIELDS];
     162             : 
     163       17226 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     164             :                           field, ftype, MAXDATEFIELDS, &nf);
     165       17226 :     if (dterr == 0)
     166       17226 :         dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
     167       17218 :     if (dterr != 0)
     168          24 :         DateTimeParseError(dterr, str, "timestamp");
     169             : 
     170       17194 :     switch (dtype)
     171             :     {
     172             :         case DTK_DATE:
     173       17078 :             if (tm2timestamp(tm, fsec, NULL, &result) != 0)
     174           8 :                 ereport(ERROR,
     175             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     176             :                          errmsg("timestamp out of range: \"%s\"", str)));
     177       17070 :             break;
     178             : 
     179             :         case DTK_EPOCH:
     180          16 :             result = SetEpochTimestamp();
     181          16 :             break;
     182             : 
     183             :         case DTK_LATE:
     184          56 :             TIMESTAMP_NOEND(result);
     185          56 :             break;
     186             : 
     187             :         case DTK_EARLY:
     188          36 :             TIMESTAMP_NOBEGIN(result);
     189          36 :             break;
     190             : 
     191             :         case DTK_INVALID:
     192           8 :             ereport(ERROR,
     193             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     194             :                      errmsg("date/time value \"%s\" is no longer supported", str)));
     195             : 
     196             :             TIMESTAMP_NOEND(result);
     197             :             break;
     198             : 
     199             :         default:
     200           0 :             elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
     201             :                  dtype, str);
     202             :             TIMESTAMP_NOEND(result);
     203             :     }
     204             : 
     205       17178 :     AdjustTimestampForTypmod(&result, typmod);
     206             : 
     207       17178 :     PG_RETURN_TIMESTAMP(result);
     208             : }
     209             : 
     210             : /* timestamp_out()
     211             :  * Convert a timestamp to external form.
     212             :  */
     213             : Datum
     214       35974 : timestamp_out(PG_FUNCTION_ARGS)
     215             : {
     216       35974 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     217             :     char       *result;
     218             :     struct pg_tm tt,
     219       35974 :                *tm = &tt;
     220             :     fsec_t      fsec;
     221             :     char        buf[MAXDATELEN + 1];
     222             : 
     223       35974 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     224         104 :         EncodeSpecialTimestamp(timestamp, buf);
     225       35870 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
     226       35870 :         EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
     227             :     else
     228           0 :         ereport(ERROR,
     229             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     230             :                  errmsg("timestamp out of range")));
     231             : 
     232       35974 :     result = pstrdup(buf);
     233       35974 :     PG_RETURN_CSTRING(result);
     234             : }
     235             : 
     236             : /*
     237             :  *      timestamp_recv          - converts external binary format to timestamp
     238             :  */
     239             : Datum
     240           0 : timestamp_recv(PG_FUNCTION_ARGS)
     241             : {
     242           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     243             : 
     244             : #ifdef NOT_USED
     245             :     Oid         typelem = PG_GETARG_OID(1);
     246             : #endif
     247           0 :     int32       typmod = PG_GETARG_INT32(2);
     248             :     Timestamp   timestamp;
     249             :     struct pg_tm tt,
     250           0 :                *tm = &tt;
     251             :     fsec_t      fsec;
     252             : 
     253           0 :     timestamp = (Timestamp) pq_getmsgint64(buf);
     254             : 
     255             :     /* range check: see if timestamp_out would like it */
     256           0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     257             :          /* ok */ ;
     258           0 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
     259           0 :              !IS_VALID_TIMESTAMP(timestamp))
     260           0 :         ereport(ERROR,
     261             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     262             :                  errmsg("timestamp out of range")));
     263             : 
     264           0 :     AdjustTimestampForTypmod(&timestamp, typmod);
     265             : 
     266           0 :     PG_RETURN_TIMESTAMP(timestamp);
     267             : }
     268             : 
     269             : /*
     270             :  *      timestamp_send          - converts timestamp to binary format
     271             :  */
     272             : Datum
     273           0 : timestamp_send(PG_FUNCTION_ARGS)
     274             : {
     275           0 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     276             :     StringInfoData buf;
     277             : 
     278           0 :     pq_begintypsend(&buf);
     279           0 :     pq_sendint64(&buf, timestamp);
     280           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     281             : }
     282             : 
     283             : Datum
     284          24 : timestamptypmodin(PG_FUNCTION_ARGS)
     285             : {
     286          24 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     287             : 
     288          24 :     PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
     289             : }
     290             : 
     291             : Datum
     292           6 : timestamptypmodout(PG_FUNCTION_ARGS)
     293             : {
     294           6 :     int32       typmod = PG_GETARG_INT32(0);
     295             : 
     296           6 :     PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
     297             : }
     298             : 
     299             : 
     300             : /*
     301             :  * timestamp_support()
     302             :  *
     303             :  * Planner support function for the timestamp_scale() and timestamptz_scale()
     304             :  * length coercion functions (we need not distinguish them here).
     305             :  */
     306             : Datum
     307           0 : timestamp_support(PG_FUNCTION_ARGS)
     308             : {
     309           0 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
     310           0 :     Node       *ret = NULL;
     311             : 
     312           0 :     if (IsA(rawreq, SupportRequestSimplify))
     313             :     {
     314           0 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
     315             : 
     316           0 :         ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall);
     317             :     }
     318             : 
     319           0 :     PG_RETURN_POINTER(ret);
     320             : }
     321             : 
     322             : /* timestamp_scale()
     323             :  * Adjust time type for specified scale factor.
     324             :  * Used by PostgreSQL type system to stuff columns.
     325             :  */
     326             : Datum
     327         310 : timestamp_scale(PG_FUNCTION_ARGS)
     328             : {
     329         310 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     330         310 :     int32       typmod = PG_GETARG_INT32(1);
     331             :     Timestamp   result;
     332             : 
     333         310 :     result = timestamp;
     334             : 
     335         310 :     AdjustTimestampForTypmod(&result, typmod);
     336             : 
     337         310 :     PG_RETURN_TIMESTAMP(result);
     338             : }
     339             : 
     340             : /*
     341             :  * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
     342             :  * Works for either timestamp or timestamptz.
     343             :  */
     344             : static void
     345       38554 : AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
     346             : {
     347             :     static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
     348             :         INT64CONST(1000000),
     349             :         INT64CONST(100000),
     350             :         INT64CONST(10000),
     351             :         INT64CONST(1000),
     352             :         INT64CONST(100),
     353             :         INT64CONST(10),
     354             :         INT64CONST(1)
     355             :     };
     356             : 
     357             :     static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
     358             :         INT64CONST(500000),
     359             :         INT64CONST(50000),
     360             :         INT64CONST(5000),
     361             :         INT64CONST(500),
     362             :         INT64CONST(50),
     363             :         INT64CONST(5),
     364             :         INT64CONST(0)
     365             :     };
     366             : 
     367       38554 :     if (!TIMESTAMP_NOT_FINITE(*time)
     368       38350 :         && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
     369             :     {
     370         608 :         if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
     371           0 :             ereport(ERROR,
     372             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     373             :                      errmsg("timestamp(%d) precision must be between %d and %d",
     374             :                             typmod, 0, MAX_TIMESTAMP_PRECISION)));
     375             : 
     376         608 :         if (*time >= INT64CONST(0))
     377             :         {
     378         360 :             *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
     379         180 :                 TimestampScales[typmod];
     380             :         }
     381             :         else
     382             :         {
     383         856 :             *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
     384         428 :                       * TimestampScales[typmod]);
     385             :         }
     386             :     }
     387       38554 : }
     388             : 
     389             : 
     390             : /* timestamptz_in()
     391             :  * Convert a string to internal form.
     392             :  */
     393             : Datum
     394       20790 : timestamptz_in(PG_FUNCTION_ARGS)
     395             : {
     396       20790 :     char       *str = PG_GETARG_CSTRING(0);
     397             : 
     398             : #ifdef NOT_USED
     399             :     Oid         typelem = PG_GETARG_OID(1);
     400             : #endif
     401       20790 :     int32       typmod = PG_GETARG_INT32(2);
     402             :     TimestampTz result;
     403             :     fsec_t      fsec;
     404             :     struct pg_tm tt,
     405       20790 :                *tm = &tt;
     406             :     int         tz;
     407             :     int         dtype;
     408             :     int         nf;
     409             :     int         dterr;
     410             :     char       *field[MAXDATEFIELDS];
     411             :     int         ftype[MAXDATEFIELDS];
     412             :     char        workbuf[MAXDATELEN + MAXDATEFIELDS];
     413             : 
     414       20790 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     415             :                           field, ftype, MAXDATEFIELDS, &nf);
     416       20790 :     if (dterr == 0)
     417       20790 :         dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
     418       20782 :     if (dterr != 0)
     419          12 :         DateTimeParseError(dterr, str, "timestamp with time zone");
     420             : 
     421       20770 :     switch (dtype)
     422             :     {
     423             :         case DTK_DATE:
     424       20660 :             if (tm2timestamp(tm, fsec, &tz, &result) != 0)
     425           8 :                 ereport(ERROR,
     426             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     427             :                          errmsg("timestamp out of range: \"%s\"", str)));
     428       20652 :             break;
     429             : 
     430             :         case DTK_EPOCH:
     431           6 :             result = SetEpochTimestamp();
     432           6 :             break;
     433             : 
     434             :         case DTK_LATE:
     435          62 :             TIMESTAMP_NOEND(result);
     436          62 :             break;
     437             : 
     438             :         case DTK_EARLY:
     439          34 :             TIMESTAMP_NOBEGIN(result);
     440          34 :             break;
     441             : 
     442             :         case DTK_INVALID:
     443           8 :             ereport(ERROR,
     444             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     445             :                      errmsg("date/time value \"%s\" is no longer supported", str)));
     446             : 
     447             :             TIMESTAMP_NOEND(result);
     448             :             break;
     449             : 
     450             :         default:
     451           0 :             elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
     452             :                  dtype, str);
     453             :             TIMESTAMP_NOEND(result);
     454             :     }
     455             : 
     456       20754 :     AdjustTimestampForTypmod(&result, typmod);
     457             : 
     458       20754 :     PG_RETURN_TIMESTAMPTZ(result);
     459             : }
     460             : 
     461             : /*
     462             :  * Try to parse a timezone specification, and return its timezone offset value
     463             :  * if it's acceptable.  Otherwise, an error is thrown.
     464             :  *
     465             :  * Note: some code paths update tm->tm_isdst, and some don't; current callers
     466             :  * don't care, so we don't bother being consistent.
     467             :  */
     468             : static int
     469         124 : parse_sane_timezone(struct pg_tm *tm, text *zone)
     470             : {
     471             :     char        tzname[TZ_STRLEN_MAX + 1];
     472             :     int         rt;
     473             :     int         tz;
     474             : 
     475         124 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
     476             : 
     477             :     /*
     478             :      * Look up the requested timezone.  First we try to interpret it as a
     479             :      * numeric timezone specification; if DecodeTimezone decides it doesn't
     480             :      * like the format, we look in the timezone abbreviation table (to handle
     481             :      * cases like "EST"), and if that also fails, we look in the timezone
     482             :      * database (to handle cases like "America/New_York").  (This matches the
     483             :      * order in which timestamp input checks the cases; it's important because
     484             :      * the timezone database unwisely uses a few zone names that are identical
     485             :      * to offset abbreviations.)
     486             :      *
     487             :      * Note pg_tzset happily parses numeric input that DecodeTimezone would
     488             :      * reject.  To avoid having it accept input that would otherwise be seen
     489             :      * as invalid, it's enough to disallow having a digit in the first
     490             :      * position of our input string.
     491             :      */
     492         124 :     if (isdigit((unsigned char) *tzname))
     493           4 :         ereport(ERROR,
     494             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     495             :                  errmsg("invalid input syntax for type %s: \"%s\"",
     496             :                         "numeric time zone", tzname),
     497             :                  errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
     498             : 
     499         120 :     rt = DecodeTimezone(tzname, &tz);
     500         120 :     if (rt != 0)
     501             :     {
     502             :         char       *lowzone;
     503             :         int         type,
     504             :                     val;
     505             :         pg_tz      *tzp;
     506             : 
     507          48 :         if (rt == DTERR_TZDISP_OVERFLOW)
     508           8 :             ereport(ERROR,
     509             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     510             :                      errmsg("numeric time zone \"%s\" out of range", tzname)));
     511          40 :         else if (rt != DTERR_BAD_FORMAT)
     512           0 :             ereport(ERROR,
     513             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     514             :                      errmsg("time zone \"%s\" not recognized", tzname)));
     515             : 
     516             :         /* DecodeTimezoneAbbrev requires lowercase input */
     517          40 :         lowzone = downcase_truncate_identifier(tzname,
     518          40 :                                                strlen(tzname),
     519             :                                                false);
     520          40 :         type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
     521             : 
     522          40 :         if (type == TZ || type == DTZ)
     523             :         {
     524             :             /* fixed-offset abbreviation */
     525           8 :             tz = -val;
     526             :         }
     527          32 :         else if (type == DYNTZ)
     528             :         {
     529             :             /* dynamic-offset abbreviation, resolve using specified time */
     530           8 :             tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
     531             :         }
     532             :         else
     533             :         {
     534             :             /* try it as a full zone name */
     535          24 :             tzp = pg_tzset(tzname);
     536          24 :             if (tzp)
     537          20 :                 tz = DetermineTimeZoneOffset(tm, tzp);
     538             :             else
     539           4 :                 ereport(ERROR,
     540             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     541             :                          errmsg("time zone \"%s\" not recognized", tzname)));
     542             :         }
     543             :     }
     544             : 
     545         108 :     return tz;
     546             : }
     547             : 
     548             : /*
     549             :  * make_timestamp_internal
     550             :  *      workhorse for make_timestamp and make_timestamptz
     551             :  */
     552             : static Timestamp
     553         132 : make_timestamp_internal(int year, int month, int day,
     554             :                         int hour, int min, double sec)
     555             : {
     556             :     struct pg_tm tm;
     557             :     TimeOffset  date;
     558             :     TimeOffset  time;
     559             :     int         dterr;
     560             :     Timestamp   result;
     561             : 
     562         132 :     tm.tm_year = year;
     563         132 :     tm.tm_mon = month;
     564         132 :     tm.tm_mday = day;
     565             : 
     566             :     /*
     567             :      * Note: we'll reject zero or negative year values.  Perhaps negatives
     568             :      * should be allowed to represent BC years?
     569             :      */
     570         132 :     dterr = ValidateDate(DTK_DATE_M, false, false, false, &tm);
     571             : 
     572         132 :     if (dterr != 0)
     573           0 :         ereport(ERROR,
     574             :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
     575             :                  errmsg("date field value out of range: %d-%02d-%02d",
     576             :                         year, month, day)));
     577             : 
     578         132 :     if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
     579           0 :         ereport(ERROR,
     580             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     581             :                  errmsg("date out of range: %d-%02d-%02d",
     582             :                         year, month, day)));
     583             : 
     584         132 :     date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
     585             : 
     586             :     /*
     587             :      * This should match the checks in DecodeTimeOnly, except that since we're
     588             :      * dealing with a float "sec" value, we also explicitly reject NaN.  (An
     589             :      * infinity input should get rejected by the range comparisons, but we
     590             :      * can't be sure how those will treat a NaN.)
     591             :      */
     592         132 :     if (hour < 0 || min < 0 || min > MINS_PER_HOUR - 1 ||
     593         132 :         isnan(sec) ||
     594         132 :         sec < 0 || sec > SECS_PER_MINUTE ||
     595         132 :         hour > HOURS_PER_DAY ||
     596             :     /* test for > 24:00:00 */
     597           0 :         (hour == HOURS_PER_DAY && (min > 0 || sec > 0)))
     598           0 :         ereport(ERROR,
     599             :                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
     600             :                  errmsg("time field value out of range: %d:%02d:%02g",
     601             :                         hour, min, sec)));
     602             : 
     603             :     /* This should match tm2time */
     604         264 :     time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
     605         132 :             * USECS_PER_SEC) + rint(sec * USECS_PER_SEC);
     606             : 
     607         132 :     result = date * USECS_PER_DAY + time;
     608             :     /* check for major overflow */
     609         132 :     if ((result - time) / USECS_PER_DAY != date)
     610           0 :         ereport(ERROR,
     611             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     612             :                  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
     613             :                         year, month, day,
     614             :                         hour, min, sec)));
     615             : 
     616             :     /* check for just-barely overflow (okay except time-of-day wraps) */
     617             :     /* caution: we want to allow 1999-12-31 24:00:00 */
     618         132 :     if ((result < 0 && date > 0) ||
     619         100 :         (result > 0 && date < -1))
     620           0 :         ereport(ERROR,
     621             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     622             :                  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
     623             :                         year, month, day,
     624             :                         hour, min, sec)));
     625             : 
     626             :     /* final range check catches just-out-of-range timestamps */
     627         132 :     if (!IS_VALID_TIMESTAMP(result))
     628           0 :         ereport(ERROR,
     629             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     630             :                  errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
     631             :                         year, month, day,
     632             :                         hour, min, sec)));
     633             : 
     634         132 :     return result;
     635             : }
     636             : 
     637             : /*
     638             :  * make_timestamp() - timestamp constructor
     639             :  */
     640             : Datum
     641           4 : make_timestamp(PG_FUNCTION_ARGS)
     642             : {
     643           4 :     int32       year = PG_GETARG_INT32(0);
     644           4 :     int32       month = PG_GETARG_INT32(1);
     645           4 :     int32       mday = PG_GETARG_INT32(2);
     646           4 :     int32       hour = PG_GETARG_INT32(3);
     647           4 :     int32       min = PG_GETARG_INT32(4);
     648           4 :     float8      sec = PG_GETARG_FLOAT8(5);
     649             :     Timestamp   result;
     650             : 
     651           4 :     result = make_timestamp_internal(year, month, mday,
     652             :                                      hour, min, sec);
     653             : 
     654           4 :     PG_RETURN_TIMESTAMP(result);
     655             : }
     656             : 
     657             : /*
     658             :  * make_timestamptz() - timestamp with time zone constructor
     659             :  */
     660             : Datum
     661           4 : make_timestamptz(PG_FUNCTION_ARGS)
     662             : {
     663           4 :     int32       year = PG_GETARG_INT32(0);
     664           4 :     int32       month = PG_GETARG_INT32(1);
     665           4 :     int32       mday = PG_GETARG_INT32(2);
     666           4 :     int32       hour = PG_GETARG_INT32(3);
     667           4 :     int32       min = PG_GETARG_INT32(4);
     668           4 :     float8      sec = PG_GETARG_FLOAT8(5);
     669             :     Timestamp   result;
     670             : 
     671           4 :     result = make_timestamp_internal(year, month, mday,
     672             :                                      hour, min, sec);
     673             : 
     674           4 :     PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
     675             : }
     676             : 
     677             : /*
     678             :  * Construct a timestamp with time zone.
     679             :  *      As above, but the time zone is specified as seventh argument.
     680             :  */
     681             : Datum
     682         124 : make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
     683             : {
     684         124 :     int32       year = PG_GETARG_INT32(0);
     685         124 :     int32       month = PG_GETARG_INT32(1);
     686         124 :     int32       mday = PG_GETARG_INT32(2);
     687         124 :     int32       hour = PG_GETARG_INT32(3);
     688         124 :     int32       min = PG_GETARG_INT32(4);
     689         124 :     float8      sec = PG_GETARG_FLOAT8(5);
     690         124 :     text       *zone = PG_GETARG_TEXT_PP(6);
     691             :     TimestampTz result;
     692             :     Timestamp   timestamp;
     693             :     struct pg_tm tt;
     694             :     int         tz;
     695             :     fsec_t      fsec;
     696             : 
     697         124 :     timestamp = make_timestamp_internal(year, month, mday,
     698             :                                         hour, min, sec);
     699             : 
     700         124 :     if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
     701           0 :         ereport(ERROR,
     702             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     703             :                  errmsg("timestamp out of range")));
     704             : 
     705         124 :     tz = parse_sane_timezone(&tt, zone);
     706             : 
     707         108 :     result = dt2local(timestamp, -tz);
     708             : 
     709         108 :     if (!IS_VALID_TIMESTAMP(result))
     710           0 :         ereport(ERROR,
     711             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     712             :                  errmsg("timestamp out of range")));
     713             : 
     714         108 :     PG_RETURN_TIMESTAMPTZ(result);
     715             : }
     716             : 
     717             : /*
     718             :  * to_timestamp(double precision)
     719             :  * Convert UNIX epoch to timestamptz.
     720             :  */
     721             : Datum
     722          28 : float8_timestamptz(PG_FUNCTION_ARGS)
     723             : {
     724          28 :     float8      seconds = PG_GETARG_FLOAT8(0);
     725             :     TimestampTz result;
     726             : 
     727             :     /* Deal with NaN and infinite inputs ... */
     728          28 :     if (isnan(seconds))
     729           4 :         ereport(ERROR,
     730             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     731             :                  errmsg("timestamp cannot be NaN")));
     732             : 
     733          24 :     if (isinf(seconds))
     734             :     {
     735           8 :         if (seconds < 0)
     736           4 :             TIMESTAMP_NOBEGIN(result);
     737             :         else
     738           4 :             TIMESTAMP_NOEND(result);
     739             :     }
     740             :     else
     741             :     {
     742             :         /* Out of range? */
     743          16 :         if (seconds <
     744             :             (float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
     745          16 :             || seconds >=
     746             :             (float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
     747           0 :             ereport(ERROR,
     748             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     749             :                      errmsg("timestamp out of range: \"%g\"", seconds)));
     750             : 
     751             :         /* Convert UNIX epoch to Postgres epoch */
     752          16 :         seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
     753             : 
     754          16 :         seconds = rint(seconds * USECS_PER_SEC);
     755          16 :         result = (int64) seconds;
     756             : 
     757             :         /* Recheck in case roundoff produces something just out of range */
     758          16 :         if (!IS_VALID_TIMESTAMP(result))
     759           0 :             ereport(ERROR,
     760             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     761             :                      errmsg("timestamp out of range: \"%g\"",
     762             :                             PG_GETARG_FLOAT8(0))));
     763             :     }
     764             : 
     765          24 :     PG_RETURN_TIMESTAMP(result);
     766             : }
     767             : 
     768             : /* timestamptz_out()
     769             :  * Convert a timestamp to external form.
     770             :  */
     771             : Datum
     772       45724 : timestamptz_out(PG_FUNCTION_ARGS)
     773             : {
     774       45724 :     TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
     775             :     char       *result;
     776             :     int         tz;
     777             :     struct pg_tm tt,
     778       45724 :                *tm = &tt;
     779             :     fsec_t      fsec;
     780             :     const char *tzn;
     781             :     char        buf[MAXDATELEN + 1];
     782             : 
     783       45724 :     if (TIMESTAMP_NOT_FINITE(dt))
     784          80 :         EncodeSpecialTimestamp(dt, buf);
     785       45644 :     else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
     786       45644 :         EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
     787             :     else
     788           0 :         ereport(ERROR,
     789             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     790             :                  errmsg("timestamp out of range")));
     791             : 
     792       45724 :     result = pstrdup(buf);
     793       45724 :     PG_RETURN_CSTRING(result);
     794             : }
     795             : 
     796             : /*
     797             :  *      timestamptz_recv            - converts external binary format to timestamptz
     798             :  */
     799             : Datum
     800           0 : timestamptz_recv(PG_FUNCTION_ARGS)
     801             : {
     802           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     803             : 
     804             : #ifdef NOT_USED
     805             :     Oid         typelem = PG_GETARG_OID(1);
     806             : #endif
     807           0 :     int32       typmod = PG_GETARG_INT32(2);
     808             :     TimestampTz timestamp;
     809             :     int         tz;
     810             :     struct pg_tm tt,
     811           0 :                *tm = &tt;
     812             :     fsec_t      fsec;
     813             : 
     814           0 :     timestamp = (TimestampTz) pq_getmsgint64(buf);
     815             : 
     816             :     /* range check: see if timestamptz_out would like it */
     817           0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
     818             :          /* ok */ ;
     819           0 :     else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
     820           0 :              !IS_VALID_TIMESTAMP(timestamp))
     821           0 :         ereport(ERROR,
     822             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     823             :                  errmsg("timestamp out of range")));
     824             : 
     825           0 :     AdjustTimestampForTypmod(&timestamp, typmod);
     826             : 
     827           0 :     PG_RETURN_TIMESTAMPTZ(timestamp);
     828             : }
     829             : 
     830             : /*
     831             :  *      timestamptz_send            - converts timestamptz to binary format
     832             :  */
     833             : Datum
     834           0 : timestamptz_send(PG_FUNCTION_ARGS)
     835             : {
     836           0 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
     837             :     StringInfoData buf;
     838             : 
     839           0 :     pq_begintypsend(&buf);
     840           0 :     pq_sendint64(&buf, timestamp);
     841           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     842             : }
     843             : 
     844             : Datum
     845         338 : timestamptztypmodin(PG_FUNCTION_ARGS)
     846             : {
     847         338 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
     848             : 
     849         338 :     PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
     850             : }
     851             : 
     852             : Datum
     853           6 : timestamptztypmodout(PG_FUNCTION_ARGS)
     854             : {
     855           6 :     int32       typmod = PG_GETARG_INT32(0);
     856             : 
     857           6 :     PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
     858             : }
     859             : 
     860             : 
     861             : /* timestamptz_scale()
     862             :  * Adjust time type for specified scale factor.
     863             :  * Used by PostgreSQL type system to stuff columns.
     864             :  */
     865             : Datum
     866         308 : timestamptz_scale(PG_FUNCTION_ARGS)
     867             : {
     868         308 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
     869         308 :     int32       typmod = PG_GETARG_INT32(1);
     870             :     TimestampTz result;
     871             : 
     872         308 :     result = timestamp;
     873             : 
     874         308 :     AdjustTimestampForTypmod(&result, typmod);
     875             : 
     876         308 :     PG_RETURN_TIMESTAMPTZ(result);
     877             : }
     878             : 
     879             : 
     880             : /* interval_in()
     881             :  * Convert a string to internal form.
     882             :  *
     883             :  * External format(s):
     884             :  *  Uses the generic date/time parsing and decoding routines.
     885             :  */
     886             : Datum
     887        6874 : interval_in(PG_FUNCTION_ARGS)
     888             : {
     889        6874 :     char       *str = PG_GETARG_CSTRING(0);
     890             : 
     891             : #ifdef NOT_USED
     892             :     Oid         typelem = PG_GETARG_OID(1);
     893             : #endif
     894        6874 :     int32       typmod = PG_GETARG_INT32(2);
     895             :     Interval   *result;
     896             :     fsec_t      fsec;
     897             :     struct pg_tm tt,
     898        6874 :                *tm = &tt;
     899             :     int         dtype;
     900             :     int         nf;
     901             :     int         range;
     902             :     int         dterr;
     903             :     char       *field[MAXDATEFIELDS];
     904             :     int         ftype[MAXDATEFIELDS];
     905             :     char        workbuf[256];
     906             : 
     907        6874 :     tm->tm_year = 0;
     908        6874 :     tm->tm_mon = 0;
     909        6874 :     tm->tm_mday = 0;
     910        6874 :     tm->tm_hour = 0;
     911        6874 :     tm->tm_min = 0;
     912        6874 :     tm->tm_sec = 0;
     913        6874 :     fsec = 0;
     914             : 
     915        6874 :     if (typmod >= 0)
     916         216 :         range = INTERVAL_RANGE(typmod);
     917             :     else
     918        6658 :         range = INTERVAL_FULL_RANGE;
     919             : 
     920        6874 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
     921             :                           ftype, MAXDATEFIELDS, &nf);
     922        6874 :     if (dterr == 0)
     923        6874 :         dterr = DecodeInterval(field, ftype, nf, range,
     924             :                                &dtype, tm, &fsec);
     925             : 
     926             :     /* if those functions think it's a bad format, try ISO8601 style */
     927        6874 :     if (dterr == DTERR_BAD_FORMAT)
     928         140 :         dterr = DecodeISO8601Interval(str,
     929             :                                       &dtype, tm, &fsec);
     930             : 
     931        6874 :     if (dterr != 0)
     932             :     {
     933          80 :         if (dterr == DTERR_FIELD_OVERFLOW)
     934           8 :             dterr = DTERR_INTERVAL_OVERFLOW;
     935          80 :         DateTimeParseError(dterr, str, "interval");
     936             :     }
     937             : 
     938        6794 :     result = (Interval *) palloc(sizeof(Interval));
     939             : 
     940        6794 :     switch (dtype)
     941             :     {
     942             :         case DTK_DELTA:
     943        6794 :             if (tm2interval(tm, fsec, result) != 0)
     944           8 :                 ereport(ERROR,
     945             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     946             :                          errmsg("interval out of range")));
     947        6786 :             break;
     948             : 
     949             :         case DTK_INVALID:
     950           0 :             ereport(ERROR,
     951             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     952             :                      errmsg("date/time value \"%s\" is no longer supported", str)));
     953             :             break;
     954             : 
     955             :         default:
     956           0 :             elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
     957             :                  dtype, str);
     958             :     }
     959             : 
     960        6786 :     AdjustIntervalForTypmod(result, typmod);
     961             : 
     962        6786 :     PG_RETURN_INTERVAL_P(result);
     963             : }
     964             : 
     965             : /* interval_out()
     966             :  * Convert a time span to external form.
     967             :  */
     968             : Datum
     969        6926 : interval_out(PG_FUNCTION_ARGS)
     970             : {
     971        6926 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
     972             :     char       *result;
     973             :     struct pg_tm tt,
     974        6926 :                *tm = &tt;
     975             :     fsec_t      fsec;
     976             :     char        buf[MAXDATELEN + 1];
     977             : 
     978        6926 :     if (interval2tm(*span, tm, &fsec) != 0)
     979           0 :         elog(ERROR, "could not convert interval to tm");
     980             : 
     981        6926 :     EncodeInterval(tm, fsec, IntervalStyle, buf);
     982             : 
     983        6926 :     result = pstrdup(buf);
     984        6926 :     PG_RETURN_CSTRING(result);
     985             : }
     986             : 
     987             : /*
     988             :  *      interval_recv           - converts external binary format to interval
     989             :  */
     990             : Datum
     991           0 : interval_recv(PG_FUNCTION_ARGS)
     992             : {
     993           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     994             : 
     995             : #ifdef NOT_USED
     996             :     Oid         typelem = PG_GETARG_OID(1);
     997             : #endif
     998           0 :     int32       typmod = PG_GETARG_INT32(2);
     999             :     Interval   *interval;
    1000             : 
    1001           0 :     interval = (Interval *) palloc(sizeof(Interval));
    1002             : 
    1003           0 :     interval->time = pq_getmsgint64(buf);
    1004           0 :     interval->day = pq_getmsgint(buf, sizeof(interval->day));
    1005           0 :     interval->month = pq_getmsgint(buf, sizeof(interval->month));
    1006             : 
    1007           0 :     AdjustIntervalForTypmod(interval, typmod);
    1008             : 
    1009           0 :     PG_RETURN_INTERVAL_P(interval);
    1010             : }
    1011             : 
    1012             : /*
    1013             :  *      interval_send           - converts interval to binary format
    1014             :  */
    1015             : Datum
    1016           0 : interval_send(PG_FUNCTION_ARGS)
    1017             : {
    1018           0 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    1019             :     StringInfoData buf;
    1020             : 
    1021           0 :     pq_begintypsend(&buf);
    1022           0 :     pq_sendint64(&buf, interval->time);
    1023           0 :     pq_sendint32(&buf, interval->day);
    1024           0 :     pq_sendint32(&buf, interval->month);
    1025           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1026             : }
    1027             : 
    1028             : /*
    1029             :  * The interval typmod stores a "range" in its high 16 bits and a "precision"
    1030             :  * in its low 16 bits.  Both contribute to defining the resolution of the
    1031             :  * type.  Range addresses resolution granules larger than one second, and
    1032             :  * precision specifies resolution below one second.  This representation can
    1033             :  * express all SQL standard resolutions, but we implement them all in terms of
    1034             :  * truncating rightward from some position.  Range is a bitmap of permitted
    1035             :  * fields, but only the temporally-smallest such field is significant to our
    1036             :  * calculations.  Precision is a count of sub-second decimal places to retain.
    1037             :  * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation
    1038             :  * semantics as choosing MAX_INTERVAL_PRECISION.
    1039             :  */
    1040             : Datum
    1041         228 : intervaltypmodin(PG_FUNCTION_ARGS)
    1042             : {
    1043         228 :     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
    1044             :     int32      *tl;
    1045             :     int         n;
    1046             :     int32       typmod;
    1047             : 
    1048         228 :     tl = ArrayGetIntegerTypmods(ta, &n);
    1049             : 
    1050             :     /*
    1051             :      * tl[0] - interval range (fields bitmask)  tl[1] - precision (optional)
    1052             :      *
    1053             :      * Note we must validate tl[0] even though it's normally guaranteed
    1054             :      * correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
    1055             :      */
    1056         228 :     if (n > 0)
    1057             :     {
    1058         228 :         switch (tl[0])
    1059             :         {
    1060             :             case INTERVAL_MASK(YEAR):
    1061             :             case INTERVAL_MASK(MONTH):
    1062             :             case INTERVAL_MASK(DAY):
    1063             :             case INTERVAL_MASK(HOUR):
    1064             :             case INTERVAL_MASK(MINUTE):
    1065             :             case INTERVAL_MASK(SECOND):
    1066             :             case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1067             :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1068             :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1069             :             case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1070             :             case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1071             :             case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1072             :             case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1073             :             case INTERVAL_FULL_RANGE:
    1074             :                 /* all OK */
    1075         228 :                 break;
    1076             :             default:
    1077           0 :                 ereport(ERROR,
    1078             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1079             :                          errmsg("invalid INTERVAL type modifier")));
    1080             :         }
    1081             :     }
    1082             : 
    1083         228 :     if (n == 1)
    1084             :     {
    1085         172 :         if (tl[0] != INTERVAL_FULL_RANGE)
    1086         172 :             typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
    1087             :         else
    1088           0 :             typmod = -1;
    1089             :     }
    1090          56 :     else if (n == 2)
    1091             :     {
    1092          56 :         if (tl[1] < 0)
    1093           0 :             ereport(ERROR,
    1094             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1095             :                      errmsg("INTERVAL(%d) precision must not be negative",
    1096             :                             tl[1])));
    1097          56 :         if (tl[1] > MAX_INTERVAL_PRECISION)
    1098             :         {
    1099           0 :             ereport(WARNING,
    1100             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1101             :                      errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
    1102             :                             tl[1], MAX_INTERVAL_PRECISION)));
    1103           0 :             typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
    1104             :         }
    1105             :         else
    1106          56 :             typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
    1107             :     }
    1108             :     else
    1109             :     {
    1110           0 :         ereport(ERROR,
    1111             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1112             :                  errmsg("invalid INTERVAL type modifier")));
    1113             :         typmod = 0;             /* keep compiler quiet */
    1114             :     }
    1115             : 
    1116         228 :     PG_RETURN_INT32(typmod);
    1117             : }
    1118             : 
    1119             : Datum
    1120           0 : intervaltypmodout(PG_FUNCTION_ARGS)
    1121             : {
    1122           0 :     int32       typmod = PG_GETARG_INT32(0);
    1123           0 :     char       *res = (char *) palloc(64);
    1124             :     int         fields;
    1125             :     int         precision;
    1126             :     const char *fieldstr;
    1127             : 
    1128           0 :     if (typmod < 0)
    1129             :     {
    1130           0 :         *res = '\0';
    1131           0 :         PG_RETURN_CSTRING(res);
    1132             :     }
    1133             : 
    1134           0 :     fields = INTERVAL_RANGE(typmod);
    1135           0 :     precision = INTERVAL_PRECISION(typmod);
    1136             : 
    1137           0 :     switch (fields)
    1138             :     {
    1139             :         case INTERVAL_MASK(YEAR):
    1140           0 :             fieldstr = " year";
    1141           0 :             break;
    1142             :         case INTERVAL_MASK(MONTH):
    1143           0 :             fieldstr = " month";
    1144           0 :             break;
    1145             :         case INTERVAL_MASK(DAY):
    1146           0 :             fieldstr = " day";
    1147           0 :             break;
    1148             :         case INTERVAL_MASK(HOUR):
    1149           0 :             fieldstr = " hour";
    1150           0 :             break;
    1151             :         case INTERVAL_MASK(MINUTE):
    1152           0 :             fieldstr = " minute";
    1153           0 :             break;
    1154             :         case INTERVAL_MASK(SECOND):
    1155           0 :             fieldstr = " second";
    1156           0 :             break;
    1157             :         case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1158           0 :             fieldstr = " year to month";
    1159           0 :             break;
    1160             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1161           0 :             fieldstr = " day to hour";
    1162           0 :             break;
    1163             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1164           0 :             fieldstr = " day to minute";
    1165           0 :             break;
    1166             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1167           0 :             fieldstr = " day to second";
    1168           0 :             break;
    1169             :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1170           0 :             fieldstr = " hour to minute";
    1171           0 :             break;
    1172             :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1173           0 :             fieldstr = " hour to second";
    1174           0 :             break;
    1175             :         case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1176           0 :             fieldstr = " minute to second";
    1177           0 :             break;
    1178             :         case INTERVAL_FULL_RANGE:
    1179           0 :             fieldstr = "";
    1180           0 :             break;
    1181             :         default:
    1182           0 :             elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
    1183             :             fieldstr = "";
    1184             :             break;
    1185             :     }
    1186             : 
    1187           0 :     if (precision != INTERVAL_FULL_PRECISION)
    1188           0 :         snprintf(res, 64, "%s(%d)", fieldstr, precision);
    1189             :     else
    1190           0 :         snprintf(res, 64, "%s", fieldstr);
    1191             : 
    1192           0 :     PG_RETURN_CSTRING(res);
    1193             : }
    1194             : 
    1195             : /*
    1196             :  * Given an interval typmod value, return a code for the least-significant
    1197             :  * field that the typmod allows to be nonzero, for instance given
    1198             :  * INTERVAL DAY TO HOUR we want to identify "hour".
    1199             :  *
    1200             :  * The results should be ordered by field significance, which means
    1201             :  * we can't use the dt.h macros YEAR etc, because for some odd reason
    1202             :  * they aren't ordered that way.  Instead, arbitrarily represent
    1203             :  * SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5.
    1204             :  */
    1205             : static int
    1206          24 : intervaltypmodleastfield(int32 typmod)
    1207             : {
    1208          24 :     if (typmod < 0)
    1209           8 :         return 0;               /* SECOND */
    1210             : 
    1211          16 :     switch (INTERVAL_RANGE(typmod))
    1212             :     {
    1213             :         case INTERVAL_MASK(YEAR):
    1214           4 :             return 5;           /* YEAR */
    1215             :         case INTERVAL_MASK(MONTH):
    1216           8 :             return 4;           /* MONTH */
    1217             :         case INTERVAL_MASK(DAY):
    1218           0 :             return 3;           /* DAY */
    1219             :         case INTERVAL_MASK(HOUR):
    1220           0 :             return 2;           /* HOUR */
    1221             :         case INTERVAL_MASK(MINUTE):
    1222           0 :             return 1;           /* MINUTE */
    1223             :         case INTERVAL_MASK(SECOND):
    1224           0 :             return 0;           /* SECOND */
    1225             :         case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
    1226           0 :             return 4;           /* MONTH */
    1227             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
    1228           0 :             return 2;           /* HOUR */
    1229             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1230           4 :             return 1;           /* MINUTE */
    1231             :         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1232           0 :             return 0;           /* SECOND */
    1233             :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
    1234           0 :             return 1;           /* MINUTE */
    1235             :         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1236           0 :             return 0;           /* SECOND */
    1237             :         case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
    1238           0 :             return 0;           /* SECOND */
    1239             :         case INTERVAL_FULL_RANGE:
    1240           0 :             return 0;           /* SECOND */
    1241             :         default:
    1242           0 :             elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
    1243             :             break;
    1244             :     }
    1245             :     return 0;                   /* can't get here, but keep compiler quiet */
    1246             : }
    1247             : 
    1248             : 
    1249             : /*
    1250             :  * interval_support()
    1251             :  *
    1252             :  * Planner support function for interval_scale().
    1253             :  *
    1254             :  * Flatten superfluous calls to interval_scale().  The interval typmod is
    1255             :  * complex to permit accepting and regurgitating all SQL standard variations.
    1256             :  * For truncation purposes, it boils down to a single, simple granularity.
    1257             :  */
    1258             : Datum
    1259          24 : interval_support(PG_FUNCTION_ARGS)
    1260             : {
    1261          24 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
    1262          24 :     Node       *ret = NULL;
    1263             : 
    1264          24 :     if (IsA(rawreq, SupportRequestSimplify))
    1265             :     {
    1266          12 :         SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
    1267          12 :         FuncExpr   *expr = req->fcall;
    1268             :         Node       *typmod;
    1269             : 
    1270             :         Assert(list_length(expr->args) >= 2);
    1271             : 
    1272          12 :         typmod = (Node *) lsecond(expr->args);
    1273             : 
    1274          12 :         if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
    1275             :         {
    1276          12 :             Node       *source = (Node *) linitial(expr->args);
    1277          12 :             int32       new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
    1278             :             bool        noop;
    1279             : 
    1280          12 :             if (new_typmod < 0)
    1281           0 :                 noop = true;
    1282             :             else
    1283             :             {
    1284          12 :                 int32       old_typmod = exprTypmod(source);
    1285             :                 int         old_least_field;
    1286             :                 int         new_least_field;
    1287             :                 int         old_precis;
    1288             :                 int         new_precis;
    1289             : 
    1290          12 :                 old_least_field = intervaltypmodleastfield(old_typmod);
    1291          12 :                 new_least_field = intervaltypmodleastfield(new_typmod);
    1292          12 :                 if (old_typmod < 0)
    1293           8 :                     old_precis = INTERVAL_FULL_PRECISION;
    1294             :                 else
    1295           4 :                     old_precis = INTERVAL_PRECISION(old_typmod);
    1296          12 :                 new_precis = INTERVAL_PRECISION(new_typmod);
    1297             : 
    1298             :                 /*
    1299             :                  * Cast is a no-op if least field stays the same or decreases
    1300             :                  * while precision stays the same or increases.  But
    1301             :                  * precision, which is to say, sub-second precision, only
    1302             :                  * affects ranges that include SECOND.
    1303             :                  */
    1304          12 :                 noop = (new_least_field <= old_least_field) &&
    1305           0 :                     (old_least_field > 0 /* SECOND */ ||
    1306           0 :                      new_precis >= MAX_INTERVAL_PRECISION ||
    1307             :                      new_precis >= old_precis);
    1308             :             }
    1309          12 :             if (noop)
    1310           0 :                 ret = relabel_to_typmod(source, new_typmod);
    1311             :         }
    1312             :     }
    1313             : 
    1314          24 :     PG_RETURN_POINTER(ret);
    1315             : }
    1316             : 
    1317             : /* interval_scale()
    1318             :  * Adjust interval type for specified fields.
    1319             :  * Used by PostgreSQL type system to stuff columns.
    1320             :  */
    1321             : Datum
    1322         120 : interval_scale(PG_FUNCTION_ARGS)
    1323             : {
    1324         120 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    1325         120 :     int32       typmod = PG_GETARG_INT32(1);
    1326             :     Interval   *result;
    1327             : 
    1328         120 :     result = palloc(sizeof(Interval));
    1329         120 :     *result = *interval;
    1330             : 
    1331         120 :     AdjustIntervalForTypmod(result, typmod);
    1332             : 
    1333         120 :     PG_RETURN_INTERVAL_P(result);
    1334             : }
    1335             : 
    1336             : /*
    1337             :  *  Adjust interval for specified precision, in both YEAR to SECOND
    1338             :  *  range and sub-second precision.
    1339             :  */
    1340             : static void
    1341        6906 : AdjustIntervalForTypmod(Interval *interval, int32 typmod)
    1342             : {
    1343             :     static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
    1344             :         INT64CONST(1000000),
    1345             :         INT64CONST(100000),
    1346             :         INT64CONST(10000),
    1347             :         INT64CONST(1000),
    1348             :         INT64CONST(100),
    1349             :         INT64CONST(10),
    1350             :         INT64CONST(1)
    1351             :     };
    1352             : 
    1353             :     static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
    1354             :         INT64CONST(500000),
    1355             :         INT64CONST(50000),
    1356             :         INT64CONST(5000),
    1357             :         INT64CONST(500),
    1358             :         INT64CONST(50),
    1359             :         INT64CONST(5),
    1360             :         INT64CONST(0)
    1361             :     };
    1362             : 
    1363             :     /*
    1364             :      * Unspecified range and precision? Then not necessary to adjust. Setting
    1365             :      * typmod to -1 is the convention for all data types.
    1366             :      */
    1367        6906 :     if (typmod >= 0)
    1368             :     {
    1369         300 :         int         range = INTERVAL_RANGE(typmod);
    1370         300 :         int         precision = INTERVAL_PRECISION(typmod);
    1371             : 
    1372             :         /*
    1373             :          * Our interpretation of intervals with a limited set of fields is
    1374             :          * that fields to the right of the last one specified are zeroed out,
    1375             :          * but those to the left of it remain valid.  Thus for example there
    1376             :          * is no operational difference between INTERVAL YEAR TO MONTH and
    1377             :          * INTERVAL MONTH.  In some cases we could meaningfully enforce that
    1378             :          * higher-order fields are zero; for example INTERVAL DAY could reject
    1379             :          * nonzero "month" field.  However that seems a bit pointless when we
    1380             :          * can't do it consistently.  (We cannot enforce a range limit on the
    1381             :          * highest expected field, since we do not have any equivalent of
    1382             :          * SQL's <interval leading field precision>.)  If we ever decide to
    1383             :          * revisit this, interval_support will likely require adjusting.
    1384             :          *
    1385             :          * Note: before PG 8.4 we interpreted a limited set of fields as
    1386             :          * actually causing a "modulo" operation on a given value, potentially
    1387             :          * losing high-order as well as low-order information.  But there is
    1388             :          * no support for such behavior in the standard, and it seems fairly
    1389             :          * undesirable on data consistency grounds anyway.  Now we only
    1390             :          * perform truncation or rounding of low-order fields.
    1391             :          */
    1392         300 :         if (range == INTERVAL_FULL_RANGE)
    1393             :         {
    1394             :             /* Do nothing... */
    1395             :         }
    1396         292 :         else if (range == INTERVAL_MASK(YEAR))
    1397             :         {
    1398          44 :             interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
    1399          44 :             interval->day = 0;
    1400          44 :             interval->time = 0;
    1401             :         }
    1402         248 :         else if (range == INTERVAL_MASK(MONTH))
    1403             :         {
    1404          48 :             interval->day = 0;
    1405          48 :             interval->time = 0;
    1406             :         }
    1407             :         /* YEAR TO MONTH */
    1408         200 :         else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
    1409             :         {
    1410          12 :             interval->day = 0;
    1411          12 :             interval->time = 0;
    1412             :         }
    1413         188 :         else if (range == INTERVAL_MASK(DAY))
    1414             :         {
    1415           8 :             interval->time = 0;
    1416             :         }
    1417         180 :         else if (range == INTERVAL_MASK(HOUR))
    1418             :         {
    1419           8 :             interval->time = (interval->time / USECS_PER_HOUR) *
    1420             :                 USECS_PER_HOUR;
    1421             :         }
    1422         172 :         else if (range == INTERVAL_MASK(MINUTE))
    1423             :         {
    1424           8 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1425             :                 USECS_PER_MINUTE;
    1426             :         }
    1427         164 :         else if (range == INTERVAL_MASK(SECOND))
    1428             :         {
    1429             :             /* fractional-second rounding will be dealt with below */
    1430             :         }
    1431             :         /* DAY TO HOUR */
    1432         148 :         else if (range == (INTERVAL_MASK(DAY) |
    1433             :                            INTERVAL_MASK(HOUR)))
    1434             :         {
    1435          16 :             interval->time = (interval->time / USECS_PER_HOUR) *
    1436             :                 USECS_PER_HOUR;
    1437             :         }
    1438             :         /* DAY TO MINUTE */
    1439         132 :         else if (range == (INTERVAL_MASK(DAY) |
    1440             :                            INTERVAL_MASK(HOUR) |
    1441             :                            INTERVAL_MASK(MINUTE)))
    1442             :         {
    1443          48 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1444             :                 USECS_PER_MINUTE;
    1445             :         }
    1446             :         /* DAY TO SECOND */
    1447          84 :         else if (range == (INTERVAL_MASK(DAY) |
    1448             :                            INTERVAL_MASK(HOUR) |
    1449             :                            INTERVAL_MASK(MINUTE) |
    1450             :                            INTERVAL_MASK(SECOND)))
    1451             :         {
    1452             :             /* fractional-second rounding will be dealt with below */
    1453             :         }
    1454             :         /* HOUR TO MINUTE */
    1455          60 :         else if (range == (INTERVAL_MASK(HOUR) |
    1456             :                            INTERVAL_MASK(MINUTE)))
    1457             :         {
    1458           8 :             interval->time = (interval->time / USECS_PER_MINUTE) *
    1459             :                 USECS_PER_MINUTE;
    1460             :         }
    1461             :         /* HOUR TO SECOND */
    1462          52 :         else if (range == (INTERVAL_MASK(HOUR) |
    1463             :                            INTERVAL_MASK(MINUTE) |
    1464             :                            INTERVAL_MASK(SECOND)))
    1465             :         {
    1466             :             /* fractional-second rounding will be dealt with below */
    1467             :         }
    1468             :         /* MINUTE TO SECOND */
    1469          36 :         else if (range == (INTERVAL_MASK(MINUTE) |
    1470             :                            INTERVAL_MASK(SECOND)))
    1471             :         {
    1472             :             /* fractional-second rounding will be dealt with below */
    1473             :         }
    1474             :         else
    1475           0 :             elog(ERROR, "unrecognized interval typmod: %d", typmod);
    1476             : 
    1477             :         /* Need to adjust sub-second precision? */
    1478         300 :         if (precision != INTERVAL_FULL_PRECISION)
    1479             :         {
    1480          44 :             if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
    1481           0 :                 ereport(ERROR,
    1482             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1483             :                          errmsg("interval(%d) precision must be between %d and %d",
    1484             :                                 precision, 0, MAX_INTERVAL_PRECISION)));
    1485             : 
    1486          44 :             if (interval->time >= INT64CONST(0))
    1487             :             {
    1488         132 :                 interval->time = ((interval->time +
    1489          88 :                                    IntervalOffsets[precision]) /
    1490          88 :                                   IntervalScales[precision]) *
    1491          44 :                     IntervalScales[precision];
    1492             :             }
    1493             :             else
    1494             :             {
    1495           0 :                 interval->time = -(((-interval->time +
    1496           0 :                                      IntervalOffsets[precision]) /
    1497           0 :                                     IntervalScales[precision]) *
    1498           0 :                                    IntervalScales[precision]);
    1499             :             }
    1500             :         }
    1501             :     }
    1502        6906 : }
    1503             : 
    1504             : /*
    1505             :  * make_interval - numeric Interval constructor
    1506             :  */
    1507             : Datum
    1508          36 : make_interval(PG_FUNCTION_ARGS)
    1509             : {
    1510          36 :     int32       years = PG_GETARG_INT32(0);
    1511          36 :     int32       months = PG_GETARG_INT32(1);
    1512          36 :     int32       weeks = PG_GETARG_INT32(2);
    1513          36 :     int32       days = PG_GETARG_INT32(3);
    1514          36 :     int32       hours = PG_GETARG_INT32(4);
    1515          36 :     int32       mins = PG_GETARG_INT32(5);
    1516          36 :     double      secs = PG_GETARG_FLOAT8(6);
    1517             :     Interval   *result;
    1518             : 
    1519             :     /*
    1520             :      * Reject out-of-range inputs.  We really ought to check the integer
    1521             :      * inputs as well, but it's not entirely clear what limits to apply.
    1522             :      */
    1523          36 :     if (isinf(secs) || isnan(secs))
    1524           8 :         ereport(ERROR,
    1525             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1526             :                  errmsg("interval out of range")));
    1527             : 
    1528          28 :     result = (Interval *) palloc(sizeof(Interval));
    1529          28 :     result->month = years * MONTHS_PER_YEAR + months;
    1530          28 :     result->day = weeks * 7 + days;
    1531             : 
    1532          28 :     secs = rint(secs * USECS_PER_SEC);
    1533          84 :     result->time = hours * ((int64) SECS_PER_HOUR * USECS_PER_SEC) +
    1534          56 :         mins * ((int64) SECS_PER_MINUTE * USECS_PER_SEC) +
    1535          28 :         (int64) secs;
    1536             : 
    1537          28 :     PG_RETURN_INTERVAL_P(result);
    1538             : }
    1539             : 
    1540             : /* EncodeSpecialTimestamp()
    1541             :  * Convert reserved timestamp data type to string.
    1542             :  */
    1543             : void
    1544         216 : EncodeSpecialTimestamp(Timestamp dt, char *str)
    1545             : {
    1546         216 :     if (TIMESTAMP_IS_NOBEGIN(dt))
    1547         100 :         strcpy(str, EARLY);
    1548         116 :     else if (TIMESTAMP_IS_NOEND(dt))
    1549         116 :         strcpy(str, LATE);
    1550             :     else                        /* shouldn't happen */
    1551           0 :         elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
    1552         216 : }
    1553             : 
    1554             : Datum
    1555         182 : now(PG_FUNCTION_ARGS)
    1556             : {
    1557         182 :     PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
    1558             : }
    1559             : 
    1560             : Datum
    1561           6 : statement_timestamp(PG_FUNCTION_ARGS)
    1562             : {
    1563           6 :     PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
    1564             : }
    1565             : 
    1566             : Datum
    1567          48 : clock_timestamp(PG_FUNCTION_ARGS)
    1568             : {
    1569          48 :     PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
    1570             : }
    1571             : 
    1572             : Datum
    1573           0 : pg_postmaster_start_time(PG_FUNCTION_ARGS)
    1574             : {
    1575           0 :     PG_RETURN_TIMESTAMPTZ(PgStartTime);
    1576             : }
    1577             : 
    1578             : Datum
    1579           0 : pg_conf_load_time(PG_FUNCTION_ARGS)
    1580             : {
    1581           0 :     PG_RETURN_TIMESTAMPTZ(PgReloadTime);
    1582             : }
    1583             : 
    1584             : /*
    1585             :  * GetCurrentTimestamp -- get the current operating system time
    1586             :  *
    1587             :  * Result is in the form of a TimestampTz value, and is expressed to the
    1588             :  * full precision of the gettimeofday() syscall
    1589             :  */
    1590             : TimestampTz
    1591     2141944 : GetCurrentTimestamp(void)
    1592             : {
    1593             :     TimestampTz result;
    1594             :     struct timeval tp;
    1595             : 
    1596     2141944 :     gettimeofday(&tp, NULL);
    1597             : 
    1598     2141944 :     result = (TimestampTz) tp.tv_sec -
    1599             :         ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
    1600     2141944 :     result = (result * USECS_PER_SEC) + tp.tv_usec;
    1601             : 
    1602     2141944 :     return result;
    1603             : }
    1604             : 
    1605             : /*
    1606             :  * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
    1607             :  */
    1608             : TimestampTz
    1609         252 : GetSQLCurrentTimestamp(int32 typmod)
    1610             : {
    1611             :     TimestampTz ts;
    1612             : 
    1613         252 :     ts = GetCurrentTransactionStartTimestamp();
    1614         252 :     if (typmod >= 0)
    1615           4 :         AdjustTimestampForTypmod(&ts, typmod);
    1616         252 :     return ts;
    1617             : }
    1618             : 
    1619             : /*
    1620             :  * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
    1621             :  */
    1622             : Timestamp
    1623          36 : GetSQLLocalTimestamp(int32 typmod)
    1624             : {
    1625             :     Timestamp   ts;
    1626             : 
    1627          36 :     ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
    1628          36 :     if (typmod >= 0)
    1629           0 :         AdjustTimestampForTypmod(&ts, typmod);
    1630          36 :     return ts;
    1631             : }
    1632             : 
    1633             : /*
    1634             :  * timeofday(*) -- returns the current time as a text.
    1635             :  */
    1636             : Datum
    1637        1600 : timeofday(PG_FUNCTION_ARGS)
    1638             : {
    1639             :     struct timeval tp;
    1640             :     char        templ[128];
    1641             :     char        buf[128];
    1642             :     pg_time_t   tt;
    1643             : 
    1644        1600 :     gettimeofday(&tp, NULL);
    1645        1600 :     tt = (pg_time_t) tp.tv_sec;
    1646        1600 :     pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
    1647        1600 :                 pg_localtime(&tt, session_timezone));
    1648        1600 :     snprintf(buf, sizeof(buf), templ, tp.tv_usec);
    1649             : 
    1650        1600 :     PG_RETURN_TEXT_P(cstring_to_text(buf));
    1651             : }
    1652             : 
    1653             : /*
    1654             :  * TimestampDifference -- convert the difference between two timestamps
    1655             :  *      into integer seconds and microseconds
    1656             :  *
    1657             :  * Both inputs must be ordinary finite timestamps (in current usage,
    1658             :  * they'll be results from GetCurrentTimestamp()).
    1659             :  *
    1660             :  * We expect start_time <= stop_time.  If not, we return zeros; for current
    1661             :  * callers there is no need to be tense about which way division rounds on
    1662             :  * negative inputs.
    1663             :  */
    1664             : void
    1665       39006 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
    1666             :                     long *secs, int *microsecs)
    1667             : {
    1668       39006 :     TimestampTz diff = stop_time - start_time;
    1669             : 
    1670       39006 :     if (diff <= 0)
    1671             :     {
    1672           0 :         *secs = 0;
    1673           0 :         *microsecs = 0;
    1674             :     }
    1675             :     else
    1676             :     {
    1677       39006 :         *secs = (long) (diff / USECS_PER_SEC);
    1678       39006 :         *microsecs = (int) (diff % USECS_PER_SEC);
    1679             :     }
    1680       39006 : }
    1681             : 
    1682             : /*
    1683             :  * TimestampDifferenceExceeds -- report whether the difference between two
    1684             :  *      timestamps is >= a threshold (expressed in milliseconds)
    1685             :  *
    1686             :  * Both inputs must be ordinary finite timestamps (in current usage,
    1687             :  * they'll be results from GetCurrentTimestamp()).
    1688             :  */
    1689             : bool
    1690      390626 : TimestampDifferenceExceeds(TimestampTz start_time,
    1691             :                            TimestampTz stop_time,
    1692             :                            int msec)
    1693             : {
    1694      390626 :     TimestampTz diff = stop_time - start_time;
    1695             : 
    1696      390626 :     return (diff >= msec * INT64CONST(1000));
    1697             : }
    1698             : 
    1699             : /*
    1700             :  * Convert a time_t to TimestampTz.
    1701             :  *
    1702             :  * We do not use time_t internally in Postgres, but this is provided for use
    1703             :  * by functions that need to interpret, say, a stat(2) result.
    1704             :  *
    1705             :  * To avoid having the function's ABI vary depending on the width of time_t,
    1706             :  * we declare the argument as pg_time_t, which is cast-compatible with
    1707             :  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
    1708             :  * This detail should be invisible to callers, at least at source code level.
    1709             :  */
    1710             : TimestampTz
    1711       29976 : time_t_to_timestamptz(pg_time_t tm)
    1712             : {
    1713             :     TimestampTz result;
    1714             : 
    1715       29976 :     result = (TimestampTz) tm -
    1716             :         ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
    1717       29976 :     result *= USECS_PER_SEC;
    1718             : 
    1719       29976 :     return result;
    1720             : }
    1721             : 
    1722             : /*
    1723             :  * Convert a TimestampTz to time_t.
    1724             :  *
    1725             :  * This too is just marginally useful, but some places need it.
    1726             :  *
    1727             :  * To avoid having the function's ABI vary depending on the width of time_t,
    1728             :  * we declare the result as pg_time_t, which is cast-compatible with
    1729             :  * time_t but always 64 bits wide (unless the platform has no 64-bit type).
    1730             :  * This detail should be invisible to callers, at least at source code level.
    1731             :  */
    1732             : pg_time_t
    1733       14246 : timestamptz_to_time_t(TimestampTz t)
    1734             : {
    1735             :     pg_time_t   result;
    1736             : 
    1737       14246 :     result = (pg_time_t) (t / USECS_PER_SEC +
    1738             :                           ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
    1739             : 
    1740       14246 :     return result;
    1741             : }
    1742             : 
    1743             : /*
    1744             :  * Produce a C-string representation of a TimestampTz.
    1745             :  *
    1746             :  * This is mostly for use in emitting messages.  The primary difference
    1747             :  * from timestamptz_out is that we force the output format to ISO.  Note
    1748             :  * also that the result is in a static buffer, not pstrdup'd.
    1749             :  */
    1750             : const char *
    1751          92 : timestamptz_to_str(TimestampTz t)
    1752             : {
    1753             :     static char buf[MAXDATELEN + 1];
    1754             :     int         tz;
    1755             :     struct pg_tm tt,
    1756          92 :                *tm = &tt;
    1757             :     fsec_t      fsec;
    1758             :     const char *tzn;
    1759             : 
    1760          92 :     if (TIMESTAMP_NOT_FINITE(t))
    1761           0 :         EncodeSpecialTimestamp(t, buf);
    1762          92 :     else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
    1763          92 :         EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
    1764             :     else
    1765           0 :         strlcpy(buf, "(timestamp out of range)", sizeof(buf));
    1766             : 
    1767          92 :     return buf;
    1768             : }
    1769             : 
    1770             : 
    1771             : void
    1772      120066 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
    1773             : {
    1774             :     TimeOffset  time;
    1775             : 
    1776      120066 :     time = jd;
    1777             : 
    1778      120066 :     *hour = time / USECS_PER_HOUR;
    1779      120066 :     time -= (*hour) * USECS_PER_HOUR;
    1780      120066 :     *min = time / USECS_PER_MINUTE;
    1781      120066 :     time -= (*min) * USECS_PER_MINUTE;
    1782      120066 :     *sec = time / USECS_PER_SEC;
    1783      120066 :     *fsec = time - (*sec * USECS_PER_SEC);
    1784      120066 : }                               /* dt2time() */
    1785             : 
    1786             : 
    1787             : /*
    1788             :  * timestamp2tm() - Convert timestamp data type to POSIX time structure.
    1789             :  *
    1790             :  * Note that year is _not_ 1900-based, but is an explicit full value.
    1791             :  * Also, month is one-based, _not_ zero-based.
    1792             :  * Returns:
    1793             :  *   0 on success
    1794             :  *  -1 on out of range
    1795             :  *
    1796             :  * If attimezone is NULL, the global timezone setting will be used.
    1797             :  */
    1798             : int
    1799      120058 : timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
    1800             : {
    1801             :     Timestamp   date;
    1802             :     Timestamp   time;
    1803             :     pg_time_t   utime;
    1804             : 
    1805             :     /* Use session timezone if caller asks for default */
    1806      120058 :     if (attimezone == NULL)
    1807      116870 :         attimezone = session_timezone;
    1808             : 
    1809      120058 :     time = dt;
    1810      120058 :     TMODULO(time, date, USECS_PER_DAY);
    1811             : 
    1812      120058 :     if (time < INT64CONST(0))
    1813             :     {
    1814       67990 :         time += USECS_PER_DAY;
    1815       67990 :         date -= 1;
    1816             :     }
    1817             : 
    1818             :     /* add offset to go from J2000 back to standard Julian date */
    1819      120058 :     date += POSTGRES_EPOCH_JDATE;
    1820             : 
    1821             :     /* Julian day routine does not work for negative Julian days */
    1822      120058 :     if (date < 0 || date > (Timestamp) INT_MAX)
    1823           0 :         return -1;
    1824             : 
    1825      120058 :     j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1826      120058 :     dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
    1827             : 
    1828             :     /* Done if no TZ conversion wanted */
    1829      120058 :     if (tzp == NULL)
    1830             :     {
    1831       55708 :         tm->tm_isdst = -1;
    1832       55708 :         tm->tm_gmtoff = 0;
    1833       55708 :         tm->tm_zone = NULL;
    1834       55708 :         if (tzn != NULL)
    1835           0 :             *tzn = NULL;
    1836       55708 :         return 0;
    1837             :     }
    1838             : 
    1839             :     /*
    1840             :      * If the time falls within the range of pg_time_t, use pg_localtime() to
    1841             :      * rotate to the local time zone.
    1842             :      *
    1843             :      * First, convert to an integral timestamp, avoiding possibly
    1844             :      * platform-specific roundoff-in-wrong-direction errors, and adjust to
    1845             :      * Unix epoch.  Then see if we can convert to pg_time_t without loss. This
    1846             :      * coding avoids hardwiring any assumptions about the width of pg_time_t,
    1847             :      * so it should behave sanely on machines without int64.
    1848             :      */
    1849       64350 :     dt = (dt - *fsec) / USECS_PER_SEC +
    1850             :         (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
    1851       64350 :     utime = (pg_time_t) dt;
    1852       64350 :     if ((Timestamp) utime == dt)
    1853             :     {
    1854       64350 :         struct pg_tm *tx = pg_localtime(&utime, attimezone);
    1855             : 
    1856       64350 :         tm->tm_year = tx->tm_year + 1900;
    1857       64350 :         tm->tm_mon = tx->tm_mon + 1;
    1858       64350 :         tm->tm_mday = tx->tm_mday;
    1859       64350 :         tm->tm_hour = tx->tm_hour;
    1860       64350 :         tm->tm_min = tx->tm_min;
    1861       64350 :         tm->tm_sec = tx->tm_sec;
    1862       64350 :         tm->tm_isdst = tx->tm_isdst;
    1863       64350 :         tm->tm_gmtoff = tx->tm_gmtoff;
    1864       64350 :         tm->tm_zone = tx->tm_zone;
    1865       64350 :         *tzp = -tm->tm_gmtoff;
    1866       64350 :         if (tzn != NULL)
    1867       51080 :             *tzn = tm->tm_zone;
    1868             :     }
    1869             :     else
    1870             :     {
    1871             :         /*
    1872             :          * When out of range of pg_time_t, treat as GMT
    1873             :          */
    1874           0 :         *tzp = 0;
    1875             :         /* Mark this as *no* time zone available */
    1876           0 :         tm->tm_isdst = -1;
    1877           0 :         tm->tm_gmtoff = 0;
    1878           0 :         tm->tm_zone = NULL;
    1879           0 :         if (tzn != NULL)
    1880           0 :             *tzn = NULL;
    1881             :     }
    1882             : 
    1883       64350 :     return 0;
    1884             : }
    1885             : 
    1886             : 
    1887             : /* tm2timestamp()
    1888             :  * Convert a tm structure to a timestamp data type.
    1889             :  * Note that year is _not_ 1900-based, but is an explicit full value.
    1890             :  * Also, month is one-based, _not_ zero-based.
    1891             :  *
    1892             :  * Returns -1 on failure (value out of range).
    1893             :  */
    1894             : int
    1895       51928 : tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
    1896             : {
    1897             :     TimeOffset  date;
    1898             :     TimeOffset  time;
    1899             : 
    1900             :     /* Prevent overflow in Julian-day routines */
    1901       51928 :     if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
    1902             :     {
    1903           8 :         *result = 0;            /* keep compiler quiet */
    1904           8 :         return -1;
    1905             :     }
    1906             : 
    1907       51920 :     date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
    1908       51920 :     time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
    1909             : 
    1910       51920 :     *result = date * USECS_PER_DAY + time;
    1911             :     /* check for major overflow */
    1912       51920 :     if ((*result - time) / USECS_PER_DAY != date)
    1913             :     {
    1914           0 :         *result = 0;            /* keep compiler quiet */
    1915           0 :         return -1;
    1916             :     }
    1917             :     /* check for just-barely overflow (okay except time-of-day wraps) */
    1918             :     /* caution: we want to allow 1999-12-31 24:00:00 */
    1919      103840 :     if ((*result < 0 && date > 0) ||
    1920       60918 :         (*result > 0 && date < -1))
    1921             :     {
    1922           0 :         *result = 0;            /* keep compiler quiet */
    1923           0 :         return -1;
    1924             :     }
    1925       51920 :     if (tzp != NULL)
    1926       30702 :         *result = dt2local(*result, -(*tzp));
    1927             : 
    1928             :     /* final range check catches just-out-of-range timestamps */
    1929       51920 :     if (!IS_VALID_TIMESTAMP(*result))
    1930             :     {
    1931           8 :         *result = 0;            /* keep compiler quiet */
    1932           8 :         return -1;
    1933             :     }
    1934             : 
    1935       51912 :     return 0;
    1936             : }
    1937             : 
    1938             : 
    1939             : /* interval2tm()
    1940             :  * Convert an interval data type to a tm structure.
    1941             :  */
    1942             : int
    1943        6944 : interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
    1944             : {
    1945             :     TimeOffset  time;
    1946             :     TimeOffset  tfrac;
    1947             : 
    1948        6944 :     tm->tm_year = span.month / MONTHS_PER_YEAR;
    1949        6944 :     tm->tm_mon = span.month % MONTHS_PER_YEAR;
    1950        6944 :     tm->tm_mday = span.day;
    1951        6944 :     time = span.time;
    1952             : 
    1953        6944 :     tfrac = time / USECS_PER_HOUR;
    1954        6944 :     time -= tfrac * USECS_PER_HOUR;
    1955        6944 :     tm->tm_hour = tfrac;
    1956        6944 :     if (!SAMESIGN(tm->tm_hour, tfrac))
    1957           0 :         ereport(ERROR,
    1958             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    1959             :                  errmsg("interval out of range")));
    1960        6944 :     tfrac = time / USECS_PER_MINUTE;
    1961        6944 :     time -= tfrac * USECS_PER_MINUTE;
    1962        6944 :     tm->tm_min = tfrac;
    1963        6944 :     tfrac = time / USECS_PER_SEC;
    1964        6944 :     *fsec = time - (tfrac * USECS_PER_SEC);
    1965        6944 :     tm->tm_sec = tfrac;
    1966             : 
    1967        6944 :     return 0;
    1968             : }
    1969             : 
    1970             : int
    1971       11526 : tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
    1972             : {
    1973       11526 :     double      total_months = (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
    1974             : 
    1975       11526 :     if (total_months > INT_MAX || total_months < INT_MIN)
    1976           8 :         return -1;
    1977       11518 :     span->month = total_months;
    1978       11518 :     span->day = tm->tm_mday;
    1979       34554 :     span->time = (((((tm->tm_hour * INT64CONST(60)) +
    1980       34554 :                      tm->tm_min) * INT64CONST(60)) +
    1981       23036 :                    tm->tm_sec) * USECS_PER_SEC) + fsec;
    1982             : 
    1983       11518 :     return 0;
    1984             : }
    1985             : 
    1986             : static TimeOffset
    1987       51920 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
    1988             : {
    1989       51920 :     return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
    1990             : }
    1991             : 
    1992             : static Timestamp
    1993       30930 : dt2local(Timestamp dt, int tz)
    1994             : {
    1995       30930 :     dt -= (tz * USECS_PER_SEC);
    1996       30930 :     return dt;
    1997             : }
    1998             : 
    1999             : 
    2000             : /*****************************************************************************
    2001             :  *   PUBLIC ROUTINES                                                         *
    2002             :  *****************************************************************************/
    2003             : 
    2004             : 
    2005             : Datum
    2006          64 : timestamp_finite(PG_FUNCTION_ARGS)
    2007             : {
    2008          64 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    2009             : 
    2010          64 :     PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
    2011             : }
    2012             : 
    2013             : Datum
    2014           0 : interval_finite(PG_FUNCTION_ARGS)
    2015             : {
    2016           0 :     PG_RETURN_BOOL(true);
    2017             : }
    2018             : 
    2019             : 
    2020             : /*----------------------------------------------------------
    2021             :  *  Relational operators for timestamp.
    2022             :  *---------------------------------------------------------*/
    2023             : 
    2024             : void
    2025          78 : GetEpochTime(struct pg_tm *tm)
    2026             : {
    2027             :     struct pg_tm *t0;
    2028          78 :     pg_time_t   epoch = 0;
    2029             : 
    2030          78 :     t0 = pg_gmtime(&epoch);
    2031             : 
    2032          78 :     if (t0 == NULL)
    2033           0 :         elog(ERROR, "could not convert epoch to timestamp: %m");
    2034             : 
    2035          78 :     tm->tm_year = t0->tm_year;
    2036          78 :     tm->tm_mon = t0->tm_mon;
    2037          78 :     tm->tm_mday = t0->tm_mday;
    2038          78 :     tm->tm_hour = t0->tm_hour;
    2039          78 :     tm->tm_min = t0->tm_min;
    2040          78 :     tm->tm_sec = t0->tm_sec;
    2041             : 
    2042          78 :     tm->tm_year += 1900;
    2043          78 :     tm->tm_mon++;
    2044          78 : }
    2045             : 
    2046             : Timestamp
    2047          74 : SetEpochTimestamp(void)
    2048             : {
    2049             :     Timestamp   dt;
    2050             :     struct pg_tm tt,
    2051          74 :                *tm = &tt;
    2052             : 
    2053          74 :     GetEpochTime(tm);
    2054             :     /* we don't bother to test for failure ... */
    2055          74 :     tm2timestamp(tm, 0, NULL, &dt);
    2056             : 
    2057          74 :     return dt;
    2058             : }                               /* SetEpochTimestamp() */
    2059             : 
    2060             : /*
    2061             :  * We are currently sharing some code between timestamp and timestamptz.
    2062             :  * The comparison functions are among them. - thomas 2001-09-25
    2063             :  *
    2064             :  *      timestamp_relop - is timestamp1 relop timestamp2
    2065             :  */
    2066             : int
    2067      368908 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
    2068             : {
    2069      368908 :     return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
    2070             : }
    2071             : 
    2072             : Datum
    2073       20310 : timestamp_eq(PG_FUNCTION_ARGS)
    2074             : {
    2075       20310 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2076       20310 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2077             : 
    2078       20310 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
    2079             : }
    2080             : 
    2081             : Datum
    2082         524 : timestamp_ne(PG_FUNCTION_ARGS)
    2083             : {
    2084         524 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2085         524 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2086             : 
    2087         524 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
    2088             : }
    2089             : 
    2090             : Datum
    2091       33930 : timestamp_lt(PG_FUNCTION_ARGS)
    2092             : {
    2093       33930 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2094       33930 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2095             : 
    2096       33930 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
    2097             : }
    2098             : 
    2099             : Datum
    2100       34308 : timestamp_gt(PG_FUNCTION_ARGS)
    2101             : {
    2102       34308 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2103       34308 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2104             : 
    2105       34308 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
    2106             : }
    2107             : 
    2108             : Datum
    2109       14856 : timestamp_le(PG_FUNCTION_ARGS)
    2110             : {
    2111       14856 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2112       14856 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2113             : 
    2114       14856 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
    2115             : }
    2116             : 
    2117             : Datum
    2118       14750 : timestamp_ge(PG_FUNCTION_ARGS)
    2119             : {
    2120       14750 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2121       14750 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2122             : 
    2123       14750 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
    2124             : }
    2125             : 
    2126             : Datum
    2127       33684 : timestamp_cmp(PG_FUNCTION_ARGS)
    2128             : {
    2129       33684 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2130       33684 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2131             : 
    2132       33684 :     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
    2133             : }
    2134             : 
    2135             : /* note: this is used for timestamptz also */
    2136             : static int
    2137      210626 : timestamp_fastcmp(Datum x, Datum y, SortSupport ssup)
    2138             : {
    2139      210626 :     Timestamp   a = DatumGetTimestamp(x);
    2140      210626 :     Timestamp   b = DatumGetTimestamp(y);
    2141             : 
    2142      210626 :     return timestamp_cmp_internal(a, b);
    2143             : }
    2144             : 
    2145             : Datum
    2146         630 : timestamp_sortsupport(PG_FUNCTION_ARGS)
    2147             : {
    2148         630 :     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
    2149             : 
    2150         630 :     ssup->comparator = timestamp_fastcmp;
    2151         630 :     PG_RETURN_VOID();
    2152             : }
    2153             : 
    2154             : Datum
    2155        2062 : timestamp_hash(PG_FUNCTION_ARGS)
    2156             : {
    2157        2062 :     return hashint8(fcinfo);
    2158             : }
    2159             : 
    2160             : Datum
    2161          40 : timestamp_hash_extended(PG_FUNCTION_ARGS)
    2162             : {
    2163          40 :     return hashint8extended(fcinfo);
    2164             : }
    2165             : 
    2166             : /*
    2167             :  * Cross-type comparison functions for timestamp vs timestamptz
    2168             :  */
    2169             : 
    2170             : Datum
    2171         404 : timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
    2172             : {
    2173         404 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2174         404 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2175             :     TimestampTz dt1;
    2176             : 
    2177         404 :     dt1 = timestamp2timestamptz(timestampVal);
    2178             : 
    2179         404 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
    2180             : }
    2181             : 
    2182             : Datum
    2183           0 : timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
    2184             : {
    2185           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2186           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2187             :     TimestampTz dt1;
    2188             : 
    2189           0 :     dt1 = timestamp2timestamptz(timestampVal);
    2190             : 
    2191           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
    2192             : }
    2193             : 
    2194             : Datum
    2195        1200 : timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
    2196             : {
    2197        1200 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2198        1200 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2199             :     TimestampTz dt1;
    2200             : 
    2201        1200 :     dt1 = timestamp2timestamptz(timestampVal);
    2202             : 
    2203        1200 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
    2204             : }
    2205             : 
    2206             : Datum
    2207        1200 : timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
    2208             : {
    2209        1200 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2210        1200 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2211             :     TimestampTz dt1;
    2212             : 
    2213        1200 :     dt1 = timestamp2timestamptz(timestampVal);
    2214             : 
    2215        1200 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
    2216             : }
    2217             : 
    2218             : Datum
    2219        1600 : timestamp_le_timestamptz(PG_FUNCTION_ARGS)
    2220             : {
    2221        1600 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2222        1600 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2223             :     TimestampTz dt1;
    2224             : 
    2225        1600 :     dt1 = timestamp2timestamptz(timestampVal);
    2226             : 
    2227        1600 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
    2228             : }
    2229             : 
    2230             : Datum
    2231        1404 : timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
    2232             : {
    2233        1404 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2234        1404 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2235             :     TimestampTz dt1;
    2236             : 
    2237        1404 :     dt1 = timestamp2timestamptz(timestampVal);
    2238             : 
    2239        1404 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
    2240             : }
    2241             : 
    2242             : Datum
    2243          48 : timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
    2244             : {
    2245          48 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(0);
    2246          48 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    2247             :     TimestampTz dt1;
    2248             : 
    2249          48 :     dt1 = timestamp2timestamptz(timestampVal);
    2250             : 
    2251          48 :     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
    2252             : }
    2253             : 
    2254             : Datum
    2255           0 : timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
    2256             : {
    2257           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2258           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2259             :     TimestampTz dt2;
    2260             : 
    2261           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2262             : 
    2263           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
    2264             : }
    2265             : 
    2266             : Datum
    2267          64 : timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
    2268             : {
    2269          64 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2270          64 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2271             :     TimestampTz dt2;
    2272             : 
    2273          64 :     dt2 = timestamp2timestamptz(timestampVal);
    2274             : 
    2275          64 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
    2276             : }
    2277             : 
    2278             : Datum
    2279           0 : timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
    2280             : {
    2281           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2282           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2283             :     TimestampTz dt2;
    2284             : 
    2285           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2286             : 
    2287           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
    2288             : }
    2289             : 
    2290             : Datum
    2291           0 : timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
    2292             : {
    2293           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2294           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2295             :     TimestampTz dt2;
    2296             : 
    2297           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2298             : 
    2299           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
    2300             : }
    2301             : 
    2302             : Datum
    2303           0 : timestamptz_le_timestamp(PG_FUNCTION_ARGS)
    2304             : {
    2305           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2306           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2307             :     TimestampTz dt2;
    2308             : 
    2309           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2310             : 
    2311           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
    2312             : }
    2313             : 
    2314             : Datum
    2315           0 : timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
    2316             : {
    2317           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2318           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2319             :     TimestampTz dt2;
    2320             : 
    2321           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2322             : 
    2323           0 :     PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
    2324             : }
    2325             : 
    2326             : Datum
    2327           0 : timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
    2328             : {
    2329           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    2330           0 :     Timestamp   timestampVal = PG_GETARG_TIMESTAMP(1);
    2331             :     TimestampTz dt2;
    2332             : 
    2333           0 :     dt2 = timestamp2timestamptz(timestampVal);
    2334             : 
    2335           0 :     PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
    2336             : }
    2337             : 
    2338             : 
    2339             : /*
    2340             :  *      interval_relop  - is interval1 relop interval2
    2341             :  *
    2342             :  * Interval comparison is based on converting interval values to a linear
    2343             :  * representation expressed in the units of the time field (microseconds,
    2344             :  * in the case of integer timestamps) with days assumed to be always 24 hours
    2345             :  * and months assumed to be always 30 days.  To avoid overflow, we need a
    2346             :  * wider-than-int64 datatype for the linear representation, so use INT128.
    2347             :  */
    2348             : 
    2349             : static inline INT128
    2350      162560 : interval_cmp_value(const Interval *interval)
    2351             : {
    2352             :     INT128      span;
    2353             :     int64       dayfraction;
    2354             :     int64       days;
    2355             : 
    2356             :     /*
    2357             :      * Separate time field into days and dayfraction, then add the month and
    2358             :      * day fields to the days part.  We cannot overflow int64 days here.
    2359             :      */
    2360      162560 :     dayfraction = interval->time % USECS_PER_DAY;
    2361      162560 :     days = interval->time / USECS_PER_DAY;
    2362      162560 :     days += interval->month * INT64CONST(30);
    2363      162560 :     days += interval->day;
    2364             : 
    2365             :     /* Widen dayfraction to 128 bits */
    2366      162560 :     span = int64_to_int128(dayfraction);
    2367             : 
    2368             :     /* Scale up days to microseconds, forming a 128-bit product */
    2369      162560 :     int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
    2370             : 
    2371      162560 :     return span;
    2372             : }
    2373             : 
    2374             : static int
    2375       80366 : interval_cmp_internal(Interval *interval1, Interval *interval2)
    2376             : {
    2377       80366 :     INT128      span1 = interval_cmp_value(interval1);
    2378       80366 :     INT128      span2 = interval_cmp_value(interval2);
    2379             : 
    2380       80366 :     return int128_compare(span1, span2);
    2381             : }
    2382             : 
    2383             : Datum
    2384        8388 : interval_eq(PG_FUNCTION_ARGS)
    2385             : {
    2386        8388 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2387        8388 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2388             : 
    2389        8388 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
    2390             : }
    2391             : 
    2392             : Datum
    2393          40 : interval_ne(PG_FUNCTION_ARGS)
    2394             : {
    2395          40 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2396          40 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2397             : 
    2398          40 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
    2399             : }
    2400             : 
    2401             : Datum
    2402       10520 : interval_lt(PG_FUNCTION_ARGS)
    2403             : {
    2404       10520 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2405       10520 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2406             : 
    2407       10520 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
    2408             : }
    2409             : 
    2410             : Datum
    2411        6896 : interval_gt(PG_FUNCTION_ARGS)
    2412             : {
    2413        6896 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2414        6896 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2415             : 
    2416        6896 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
    2417             : }
    2418             : 
    2419             : Datum
    2420        4068 : interval_le(PG_FUNCTION_ARGS)
    2421             : {
    2422        4068 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2423        4068 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2424             : 
    2425        4068 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
    2426             : }
    2427             : 
    2428             : Datum
    2429        3684 : interval_ge(PG_FUNCTION_ARGS)
    2430             : {
    2431        3684 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2432        3684 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2433             : 
    2434        3684 :     PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
    2435             : }
    2436             : 
    2437             : Datum
    2438       46482 : interval_cmp(PG_FUNCTION_ARGS)
    2439             : {
    2440       46482 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    2441       46482 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    2442             : 
    2443       46482 :     PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
    2444             : }
    2445             : 
    2446             : /*
    2447             :  * Hashing for intervals
    2448             :  *
    2449             :  * We must produce equal hashvals for values that interval_cmp_internal()
    2450             :  * considers equal.  So, compute the net span the same way it does,
    2451             :  * and then hash that.
    2452             :  */
    2453             : Datum
    2454          48 : interval_hash(PG_FUNCTION_ARGS)
    2455             : {
    2456          48 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    2457          48 :     INT128      span = interval_cmp_value(interval);
    2458             :     int64       span64;
    2459             : 
    2460             :     /*
    2461             :      * Use only the least significant 64 bits for hashing.  The upper 64 bits
    2462             :      * seldom add any useful information, and besides we must do it like this
    2463             :      * for compatibility with hashes calculated before use of INT128 was
    2464             :      * introduced.
    2465             :      */
    2466          48 :     span64 = int128_to_int64(span);
    2467             : 
    2468          48 :     return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
    2469             : }
    2470             : 
    2471             : Datum
    2472          40 : interval_hash_extended(PG_FUNCTION_ARGS)
    2473             : {
    2474          40 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    2475          40 :     INT128      span = interval_cmp_value(interval);
    2476             :     int64       span64;
    2477             : 
    2478             :     /* Same approach as interval_hash */
    2479          40 :     span64 = int128_to_int64(span);
    2480             : 
    2481          40 :     return DirectFunctionCall2(hashint8extended, Int64GetDatumFast(span64),
    2482             :                                PG_GETARG_DATUM(1));
    2483             : }
    2484             : 
    2485             : /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
    2486             :  *
    2487             :  * Algorithm is per SQL spec.  This is much harder than you'd think
    2488             :  * because the spec requires us to deliver a non-null answer in some cases
    2489             :  * where some of the inputs are null.
    2490             :  */
    2491             : Datum
    2492          48 : overlaps_timestamp(PG_FUNCTION_ARGS)
    2493             : {
    2494             :     /*
    2495             :      * The arguments are Timestamps, but we leave them as generic Datums to
    2496             :      * avoid unnecessary conversions between value and reference forms --- not
    2497             :      * to mention possible dereferences of null pointers.
    2498             :      */
    2499          48 :     Datum       ts1 = PG_GETARG_DATUM(0);
    2500          48 :     Datum       te1 = PG_GETARG_DATUM(1);
    2501          48 :     Datum       ts2 = PG_GETARG_DATUM(2);
    2502          48 :     Datum       te2 = PG_GETARG_DATUM(3);
    2503          48 :     bool        ts1IsNull = PG_ARGISNULL(0);
    2504          48 :     bool        te1IsNull = PG_ARGISNULL(1);
    2505          48 :     bool        ts2IsNull = PG_ARGISNULL(2);
    2506          48 :     bool        te2IsNull = PG_ARGISNULL(3);
    2507             : 
    2508             : #define TIMESTAMP_GT(t1,t2) \
    2509             :     DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
    2510             : #define TIMESTAMP_LT(t1,t2) \
    2511             :     DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
    2512             : 
    2513             :     /*
    2514             :      * If both endpoints of interval 1 are null, the result is null (unknown).
    2515             :      * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
    2516             :      * take ts1 as the lesser endpoint.
    2517             :      */
    2518          48 :     if (ts1IsNull)
    2519             :     {
    2520           0 :         if (te1IsNull)
    2521           0 :             PG_RETURN_NULL();
    2522             :         /* swap null for non-null */
    2523           0 :         ts1 = te1;
    2524           0 :         te1IsNull = true;
    2525             :     }
    2526          48 :     else if (!te1IsNull)
    2527             :     {
    2528          48 :         if (TIMESTAMP_GT(ts1, te1))
    2529             :         {
    2530           0 :             Datum       tt = ts1;
    2531             : 
    2532           0 :             ts1 = te1;
    2533           0 :             te1 = tt;
    2534             :         }
    2535             :     }
    2536             : 
    2537             :     /* Likewise for interval 2. */
    2538          48 :     if (ts2IsNull)
    2539             :     {
    2540           0 :         if (te2IsNull)
    2541           0 :             PG_RETURN_NULL();
    2542             :         /* swap null for non-null */
    2543           0 :         ts2 = te2;
    2544           0 :         te2IsNull = true;
    2545             :     }
    2546          48 :     else if (!te2IsNull)
    2547             :     {
    2548          48 :         if (TIMESTAMP_GT(ts2, te2))
    2549             :         {
    2550           0 :             Datum       tt = ts2;
    2551             : 
    2552           0 :             ts2 = te2;
    2553           0 :             te2 = tt;
    2554             :         }
    2555             :     }
    2556             : 
    2557             :     /*
    2558             :      * At this point neither ts1 nor ts2 is null, so we can consider three
    2559             :      * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
    2560             :      */
    2561          48 :     if (TIMESTAMP_GT(ts1, ts2))
    2562             :     {
    2563             :         /*
    2564             :          * This case is ts1 < te2 OR te1 < te2, which may look redundant but
    2565             :          * in the presence of nulls it's not quite completely so.
    2566             :          */
    2567           0 :         if (te2IsNull)
    2568           0 :             PG_RETURN_NULL();
    2569           0 :         if (TIMESTAMP_LT(ts1, te2))
    2570           0 :             PG_RETURN_BOOL(true);
    2571           0 :         if (te1IsNull)
    2572           0 :             PG_RETURN_NULL();
    2573             : 
    2574             :         /*
    2575             :          * If te1 is not null then we had ts1 <= te1 above, and we just found
    2576             :          * ts1 >= te2, hence te1 >= te2.
    2577             :          */
    2578           0 :         PG_RETURN_BOOL(false);
    2579             :     }
    2580          48 :     else if (TIMESTAMP_LT(ts1, ts2))
    2581             :     {
    2582             :         /* This case is ts2 < te1 OR te2 < te1 */
    2583          40 :         if (te1IsNull)
    2584           0 :             PG_RETURN_NULL();
    2585          40 :         if (TIMESTAMP_LT(ts2, te1))
    2586          16 :             PG_RETURN_BOOL(true);
    2587          24 :         if (te2IsNull)
    2588           0 :             PG_RETURN_NULL();
    2589             : 
    2590             :         /*
    2591             :          * If te2 is not null then we had ts2 <= te2 above, and we just found
    2592             :          * ts2 >= te1, hence te2 >= te1.
    2593             :          */
    2594          24 :         PG_RETURN_BOOL(false);
    2595             :     }
    2596             :     else
    2597             :     {
    2598             :         /*
    2599             :          * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
    2600             :          * rather silly way of saying "true if both are non-null, else null".
    2601             :          */
    2602           8 :         if (te1IsNull || te2IsNull)
    2603           0 :             PG_RETURN_NULL();
    2604           8 :         PG_RETURN_BOOL(true);
    2605             :     }
    2606             : 
    2607             : #undef TIMESTAMP_GT
    2608             : #undef TIMESTAMP_LT
    2609             : }
    2610             : 
    2611             : 
    2612             : /*----------------------------------------------------------
    2613             :  *  "Arithmetic" operators on date/times.
    2614             :  *---------------------------------------------------------*/
    2615             : 
    2616             : Datum
    2617           0 : timestamp_smaller(PG_FUNCTION_ARGS)
    2618             : {
    2619           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2620           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2621             :     Timestamp   result;
    2622             : 
    2623             :     /* use timestamp_cmp_internal to be sure this agrees with comparisons */
    2624           0 :     if (timestamp_cmp_internal(dt1, dt2) < 0)
    2625           0 :         result = dt1;
    2626             :     else
    2627           0 :         result = dt2;
    2628           0 :     PG_RETURN_TIMESTAMP(result);
    2629             : }
    2630             : 
    2631             : Datum
    2632           0 : timestamp_larger(PG_FUNCTION_ARGS)
    2633             : {
    2634           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2635           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2636             :     Timestamp   result;
    2637             : 
    2638           0 :     if (timestamp_cmp_internal(dt1, dt2) > 0)
    2639           0 :         result = dt1;
    2640             :     else
    2641           0 :         result = dt2;
    2642           0 :     PG_RETURN_TIMESTAMP(result);
    2643             : }
    2644             : 
    2645             : 
    2646             : Datum
    2647        5134 : timestamp_mi(PG_FUNCTION_ARGS)
    2648             : {
    2649        5134 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    2650        5134 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    2651             :     Interval   *result;
    2652             : 
    2653        5134 :     result = (Interval *) palloc(sizeof(Interval));
    2654             : 
    2655        5134 :     if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
    2656           0 :         ereport(ERROR,
    2657             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2658             :                  errmsg("cannot subtract infinite timestamps")));
    2659             : 
    2660        5134 :     result->time = dt1 - dt2;
    2661             : 
    2662        5134 :     result->month = 0;
    2663        5134 :     result->day = 0;
    2664             : 
    2665             :     /*----------
    2666             :      *  This is wrong, but removing it breaks a lot of regression tests.
    2667             :      *  For example:
    2668             :      *
    2669             :      *  test=> SET timezone = 'EST5EDT';
    2670             :      *  test=> SELECT
    2671             :      *  test-> ('2005-10-30 13:22:00-05'::timestamptz -
    2672             :      *  test(>   '2005-10-29 13:22:00-04'::timestamptz);
    2673             :      *  ?column?
    2674             :      *  ----------------
    2675             :      *   1 day 01:00:00
    2676             :      *   (1 row)
    2677             :      *
    2678             :      *  so adding that to the first timestamp gets:
    2679             :      *
    2680             :      *   test=> SELECT
    2681             :      *   test-> ('2005-10-29 13:22:00-04'::timestamptz +
    2682             :      *   test(> ('2005-10-30 13:22:00-05'::timestamptz -
    2683             :      *   test(>  '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
    2684             :      *      timezone
    2685             :      *  --------------------
    2686             :      *  2005-10-30 14:22:00
    2687             :      *  (1 row)
    2688             :      *----------
    2689             :      */
    2690        5134 :     result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
    2691             :                                                    IntervalPGetDatum(result)));
    2692             : 
    2693        5134 :     PG_RETURN_INTERVAL_P(result);
    2694             : }
    2695             : 
    2696             : /*
    2697             :  *  interval_justify_interval()
    2698             :  *
    2699             :  *  Adjust interval so 'month', 'day', and 'time' portions are within
    2700             :  *  customary bounds.  Specifically:
    2701             :  *
    2702             :  *      0 <= abs(time) < 24 hours
    2703             :  *      0 <= abs(day)  < 30 days
    2704             :  *
    2705             :  *  Also, the sign bit on all three fields is made equal, so either
    2706             :  *  all three fields are negative or all are positive.
    2707             :  */
    2708             : Datum
    2709           4 : interval_justify_interval(PG_FUNCTION_ARGS)
    2710             : {
    2711           4 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    2712             :     Interval   *result;
    2713             :     TimeOffset  wholeday;
    2714             :     int32       wholemonth;
    2715             : 
    2716           4 :     result = (Interval *) palloc(sizeof(Interval));
    2717           4 :     result->month = span->month;
    2718           4 :     result->day = span->day;
    2719           4 :     result->time = span->time;
    2720             : 
    2721           4 :     TMODULO(result->time, wholeday, USECS_PER_DAY);
    2722           4 :     result->day += wholeday; /* could overflow... */
    2723             : 
    2724           4 :     wholemonth = result->day / DAYS_PER_MONTH;
    2725           4 :     result->day -= wholemonth * DAYS_PER_MONTH;
    2726           4 :     result->month += wholemonth;
    2727             : 
    2728           8 :     if (result->month > 0 &&
    2729           8 :         (result->day < 0 || (result->day == 0 && result->time < 0)))
    2730             :     {
    2731           4 :         result->day += DAYS_PER_MONTH;
    2732           4 :         result->month--;
    2733             :     }
    2734           0 :     else if (result->month < 0 &&
    2735           0 :              (result->day > 0 || (result->day == 0 && result->time > 0)))
    2736             :     {
    2737           0 :         result->day -= DAYS_PER_MONTH;
    2738           0 :         result->month++;
    2739             :     }
    2740             : 
    2741           4 :     if (result->day > 0 && result->time < 0)
    2742             :     {
    2743           4 :         result->time += USECS_PER_DAY;
    2744           4 :         result->day--;
    2745             :     }
    2746           0 :     else if (result->day < 0 && result->time > 0)
    2747             :     {
    2748           0 :         result->time -= USECS_PER_DAY;
    2749           0 :         result->day++;
    2750             :     }
    2751             : 
    2752           4 :     PG_RETURN_INTERVAL_P(result);
    2753             : }
    2754             : 
    2755             : /*
    2756             :  *  interval_justify_hours()
    2757             :  *
    2758             :  *  Adjust interval so 'time' contains less than a whole day, adding
    2759             :  *  the excess to 'day'.  This is useful for
    2760             :  *  situations (such as non-TZ) where '1 day' = '24 hours' is valid,
    2761             :  *  e.g. interval subtraction and division.
    2762             :  */
    2763             : Datum
    2764        5578 : interval_justify_hours(PG_FUNCTION_ARGS)
    2765             : {
    2766        5578 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    2767             :     Interval   *result;
    2768             :     TimeOffset  wholeday;
    2769             : 
    2770        5578 :     result = (Interval *) palloc(sizeof(Interval));
    2771        5578 :     result->month = span->month;
    2772        5578 :     result->day = span->day;
    2773        5578 :     result->time = span->time;
    2774             : 
    2775        5578 :     TMODULO(result->time, wholeday, USECS_PER_DAY);
    2776        5578 :     result->day += wholeday; /* could overflow... */
    2777             : 
    2778        5578 :     if (result->day > 0 && result->time < 0)
    2779             :     {
    2780           0 :         result->time += USECS_PER_DAY;
    2781           0 :         result->day--;
    2782             :     }
    2783        5578 :     else if (result->day < 0 && result->time > 0)
    2784             :     {
    2785           0 :         result->time -= USECS_PER_DAY;
    2786           0 :         result->day++;
    2787             :     }
    2788             : 
    2789        5578 :     PG_RETURN_INTERVAL_P(result);
    2790             : }
    2791             : 
    2792             : /*
    2793             :  *  interval_justify_days()
    2794             :  *
    2795             :  *  Adjust interval so 'day' contains less than 30 days, adding
    2796             :  *  the excess to 'month'.
    2797             :  */
    2798             : Datum
    2799         444 : interval_justify_days(PG_FUNCTION_ARGS)
    2800             : {
    2801         444 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    2802             :     Interval   *result;
    2803             :     int32       wholemonth;
    2804             : 
    2805         444 :     result = (Interval *) palloc(sizeof(Interval));
    2806         444 :     result->month = span->month;
    2807         444 :     result->day = span->day;
    2808         444 :     result->time = span->time;
    2809             : 
    2810         444 :     wholemonth = result->day / DAYS_PER_MONTH;
    2811         444 :     result->day -= wholemonth * DAYS_PER_MONTH;
    2812         444 :     result->month += wholemonth;
    2813             : 
    2814         444 :     if (result->month > 0 && result->day < 0)
    2815             :     {
    2816           0 :         result->day += DAYS_PER_MONTH;
    2817           0 :         result->month--;
    2818             :     }
    2819         444 :     else if (result->month < 0 && result->day > 0)
    2820             :     {
    2821           0 :         result->day -= DAYS_PER_MONTH;
    2822           0 :         result->month++;
    2823             :     }
    2824             : 
    2825         444 :     PG_RETURN_INTERVAL_P(result);
    2826             : }
    2827             : 
    2828             : /* timestamp_pl_interval()
    2829             :  * Add an interval to a timestamp data type.
    2830             :  * Note that interval has provisions for qualitative year/month and day
    2831             :  *  units, so try to do the right thing with them.
    2832             :  * To add a month, increment the month, and use the same day of month.
    2833             :  * Then, if the next month has fewer days, set the day of month
    2834             :  *  to the last day of month.
    2835             :  * To add a day, increment the mday, and use the same time of day.
    2836             :  * Lastly, add in the "quantitative time".
    2837             :  */
    2838             : Datum
    2839        5060 : timestamp_pl_interval(PG_FUNCTION_ARGS)
    2840             : {
    2841        5060 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    2842        5060 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2843             :     Timestamp   result;
    2844             : 
    2845        5060 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    2846          16 :         result = timestamp;
    2847             :     else
    2848             :     {
    2849        5044 :         if (span->month != 0)
    2850             :         {
    2851             :             struct pg_tm tt,
    2852        1684 :                        *tm = &tt;
    2853             :             fsec_t      fsec;
    2854             : 
    2855        1684 :             if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    2856           0 :                 ereport(ERROR,
    2857             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2858             :                          errmsg("timestamp out of range")));
    2859             : 
    2860        1684 :             tm->tm_mon += span->month;
    2861        1684 :             if (tm->tm_mon > MONTHS_PER_YEAR)
    2862             :             {
    2863         920 :                 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
    2864         920 :                 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
    2865             :             }
    2866         764 :             else if (tm->tm_mon < 1)
    2867             :             {
    2868         764 :                 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
    2869         764 :                 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
    2870             :             }
    2871             : 
    2872             :             /* adjust for end of month boundary problems... */
    2873        1684 :             if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    2874           8 :                 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
    2875             : 
    2876        1684 :             if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
    2877           0 :                 ereport(ERROR,
    2878             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2879             :                          errmsg("timestamp out of range")));
    2880             :         }
    2881             : 
    2882        5044 :         if (span->day != 0)
    2883             :         {
    2884             :             struct pg_tm tt,
    2885        2032 :                        *tm = &tt;
    2886             :             fsec_t      fsec;
    2887             :             int         julian;
    2888             : 
    2889        2032 :             if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    2890           0 :                 ereport(ERROR,
    2891             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2892             :                          errmsg("timestamp out of range")));
    2893             : 
    2894             :             /* Add days by converting to and from Julian */
    2895        2032 :             julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
    2896        2032 :             j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2897             : 
    2898        2032 :             if (tm2timestamp(tm, fsec, NULL, &timestamp) != 0)
    2899           0 :                 ereport(ERROR,
    2900             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2901             :                          errmsg("timestamp out of range")));
    2902             :         }
    2903             : 
    2904        5044 :         timestamp += span->time;
    2905             : 
    2906        5044 :         if (!IS_VALID_TIMESTAMP(timestamp))
    2907           0 :             ereport(ERROR,
    2908             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2909             :                      errmsg("timestamp out of range")));
    2910             : 
    2911        5044 :         result = timestamp;
    2912             :     }
    2913             : 
    2914        5060 :     PG_RETURN_TIMESTAMP(result);
    2915             : }
    2916             : 
    2917             : Datum
    2918        1216 : timestamp_mi_interval(PG_FUNCTION_ARGS)
    2919             : {
    2920        1216 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    2921        1216 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2922             :     Interval    tspan;
    2923             : 
    2924        1216 :     tspan.month = -span->month;
    2925        1216 :     tspan.day = -span->day;
    2926        1216 :     tspan.time = -span->time;
    2927             : 
    2928        1216 :     return DirectFunctionCall2(timestamp_pl_interval,
    2929             :                                TimestampGetDatum(timestamp),
    2930             :                                PointerGetDatum(&tspan));
    2931             : }
    2932             : 
    2933             : 
    2934             : /* timestamptz_pl_interval()
    2935             :  * Add an interval to a timestamp with time zone data type.
    2936             :  * Note that interval has provisions for qualitative year/month
    2937             :  *  units, so try to do the right thing with them.
    2938             :  * To add a month, increment the month, and use the same day of month.
    2939             :  * Then, if the next month has fewer days, set the day of month
    2940             :  *  to the last day of month.
    2941             :  * Lastly, add in the "quantitative time".
    2942             :  */
    2943             : Datum
    2944        4634 : timestamptz_pl_interval(PG_FUNCTION_ARGS)
    2945             : {
    2946        4634 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    2947        4634 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    2948             :     TimestampTz result;
    2949             :     int         tz;
    2950             : 
    2951        4634 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    2952          16 :         result = timestamp;
    2953             :     else
    2954             :     {
    2955        4618 :         if (span->month != 0)
    2956             :         {
    2957             :             struct pg_tm tt,
    2958        1440 :                        *tm = &tt;
    2959             :             fsec_t      fsec;
    2960             : 
    2961        1440 :             if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    2962           0 :                 ereport(ERROR,
    2963             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2964             :                          errmsg("timestamp out of range")));
    2965             : 
    2966        1440 :             tm->tm_mon += span->month;
    2967        1440 :             if (tm->tm_mon > MONTHS_PER_YEAR)
    2968             :             {
    2969         584 :                 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
    2970         584 :                 tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
    2971             :             }
    2972         856 :             else if (tm->tm_mon < 1)
    2973             :             {
    2974         656 :                 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
    2975         656 :                 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
    2976             :             }
    2977             : 
    2978             :             /* adjust for end of month boundary problems... */
    2979        1440 :             if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    2980          36 :                 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
    2981             : 
    2982        1440 :             tz = DetermineTimeZoneOffset(tm, session_timezone);
    2983             : 
    2984        1440 :             if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
    2985           0 :                 ereport(ERROR,
    2986             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2987             :                          errmsg("timestamp out of range")));
    2988             :         }
    2989             : 
    2990        4618 :         if (span->day != 0)
    2991             :         {
    2992             :             struct pg_tm tt,
    2993        2266 :                        *tm = &tt;
    2994             :             fsec_t      fsec;
    2995             :             int         julian;
    2996             : 
    2997        2266 :             if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    2998           0 :                 ereport(ERROR,
    2999             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3000             :                          errmsg("timestamp out of range")));
    3001             : 
    3002             :             /* Add days by converting to and from Julian */
    3003        2266 :             julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
    3004        2266 :             j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    3005             : 
    3006        2266 :             tz = DetermineTimeZoneOffset(tm, session_timezone);
    3007             : 
    3008        2266 :             if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
    3009           0 :                 ereport(ERROR,
    3010             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3011             :                          errmsg("timestamp out of range")));
    3012             :         }
    3013             : 
    3014        4618 :         timestamp += span->time;
    3015             : 
    3016        4618 :         if (!IS_VALID_TIMESTAMP(timestamp))
    3017           0 :             ereport(ERROR,
    3018             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3019             :                      errmsg("timestamp out of range")));
    3020             : 
    3021        4618 :         result = timestamp;
    3022             :     }
    3023             : 
    3024        4634 :     PG_RETURN_TIMESTAMP(result);
    3025             : }
    3026             : 
    3027             : Datum
    3028        1074 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
    3029             : {
    3030        1074 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    3031        1074 :     Interval   *span = PG_GETARG_INTERVAL_P(1);
    3032             :     Interval    tspan;
    3033             : 
    3034        1074 :     tspan.month = -span->month;
    3035        1074 :     tspan.day = -span->day;
    3036        1074 :     tspan.time = -span->time;
    3037             : 
    3038        1074 :     return DirectFunctionCall2(timestamptz_pl_interval,
    3039             :                                TimestampGetDatum(timestamp),
    3040             :                                PointerGetDatum(&tspan));
    3041             : }
    3042             : 
    3043             : 
    3044             : Datum
    3045        2494 : interval_um(PG_FUNCTION_ARGS)
    3046             : {
    3047        2494 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
    3048             :     Interval   *result;
    3049             : 
    3050        2494 :     result = (Interval *) palloc(sizeof(Interval));
    3051             : 
    3052        2494 :     result->time = -interval->time;
    3053             :     /* overflow check copied from int4um */
    3054        2494 :     if (interval->time != 0 && SAMESIGN(result->time, interval->time))
    3055           0 :         ereport(ERROR,
    3056             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3057             :                  errmsg("interval out of range")));
    3058        2494 :     result->day = -interval->day;
    3059        2494 :     if (interval->day != 0 && SAMESIGN(result->day, interval->day))
    3060           0 :         ereport(ERROR,
    3061             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3062             :                  errmsg("interval out of range")));
    3063        2494 :     result->month = -interval->month;
    3064        2494 :     if (interval->month != 0 && SAMESIGN(result->month, interval->month))
    3065           0 :         ereport(ERROR,
    3066             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3067             :                  errmsg("interval out of range")));
    3068             : 
    3069        2494 :     PG_RETURN_INTERVAL_P(result);
    3070             : }
    3071             : 
    3072             : 
    3073             : Datum
    3074           0 : interval_smaller(PG_FUNCTION_ARGS)
    3075             : {
    3076           0 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    3077           0 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    3078             :     Interval   *result;
    3079             : 
    3080             :     /* use interval_cmp_internal to be sure this agrees with comparisons */
    3081           0 :     if (interval_cmp_internal(interval1, interval2) < 0)
    3082           0 :         result = interval1;
    3083             :     else
    3084           0 :         result = interval2;
    3085           0 :     PG_RETURN_INTERVAL_P(result);
    3086             : }
    3087             : 
    3088             : Datum
    3089           0 : interval_larger(PG_FUNCTION_ARGS)
    3090             : {
    3091           0 :     Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
    3092           0 :     Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
    3093             :     Interval   *result;
    3094             : 
    3095           0 :     if (interval_cmp_internal(interval1, interval2) > 0)
    3096           0 :         result = interval1;
    3097             :     else
    3098           0 :         result = interval2;
    3099           0 :     PG_RETURN_INTERVAL_P(result);
    3100             : }
    3101             : 
    3102             : Datum
    3103         244 : interval_pl(PG_FUNCTION_ARGS)
    3104             : {
    3105         244 :     Interval   *span1 = PG_GETARG_INTERVAL_P(0);
    3106         244 :     Interval   *span2 = PG_GETARG_INTERVAL_P(1);
    3107             :     Interval   *result;
    3108             : 
    3109         244 :     result = (Interval *) palloc(sizeof(Interval));
    3110             : 
    3111         244 :     result->month = span1->month + span2->month;
    3112             :     /* overflow check copied from int4pl */
    3113         484 :     if (SAMESIGN(span1->month, span2->month) &&
    3114         240 :         !SAMESIGN(result->month, span1->month))
    3115           0 :         ereport(ERROR,
    3116             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3117             :                  errmsg("interval out of range")));
    3118             : 
    3119         244 :     result->day = span1->day + span2->day;
    3120         488 :     if (SAMESIGN(span1->day, span2->day) &&
    3121         244 :         !SAMESIGN(result->day, span1->day))
    3122           0 :         ereport(ERROR,
    3123             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3124             :                  errmsg("interval out of range")));
    3125             : 
    3126         244 :     result->time = span1->time + span2->time;
    3127         480 :     if (SAMESIGN(span1->time, span2->time) &&
    3128         236 :         !SAMESIGN(result->time, span1->time))
    3129           0 :         ereport(ERROR,
    3130             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3131             :                  errmsg("interval out of range")));
    3132             : 
    3133         244 :     PG_RETURN_INTERVAL_P(result);
    3134             : }
    3135             : 
    3136             : Datum
    3137        1368 : interval_mi(PG_FUNCTION_ARGS)
    3138             : {
    3139        1368 :     Interval   *span1 = PG_GETARG_INTERVAL_P(0);
    3140        1368 :     Interval   *span2 = PG_GETARG_INTERVAL_P(1);
    3141             :     Interval   *result;
    3142             : 
    3143        1368 :     result = (Interval *) palloc(sizeof(Interval));
    3144             : 
    3145        1368 :     result->month = span1->month - span2->month;
    3146             :     /* overflow check copied from int4mi */
    3147        1368 :     if (!SAMESIGN(span1->month, span2->month) &&
    3148           0 :         !SAMESIGN(result->month, span1->month))
    3149           0 :         ereport(ERROR,
    3150             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3151             :                  errmsg("interval out of range")));
    3152             : 
    3153        1368 :     result->day = span1->day - span2->day;
    3154        2010 :     if (!SAMESIGN(span1->day, span2->day) &&
    3155         642 :         !SAMESIGN(result->day, span1->day))
    3156           0 :         ereport(ERROR,
    3157             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3158             :                  errmsg("interval out of range")));
    3159             : 
    3160        1368 :     result->time = span1->time - span2->time;
    3161        2010 :     if (!SAMESIGN(span1->time, span2->time) &&
    3162         642 :         !SAMESIGN(result->time, span1->time))
    3163           0 :         ereport(ERROR,
    3164             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3165             :                  errmsg("interval out of range")));
    3166             : 
    3167        1368 :     PG_RETURN_INTERVAL_P(result);
    3168             : }
    3169             : 
    3170             : /*
    3171             :  *  There is no interval_abs():  it is unclear what value to return:
    3172             :  *    http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
    3173             :  *    http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
    3174             :  */
    3175             : 
    3176             : Datum
    3177        2266 : interval_mul(PG_FUNCTION_ARGS)
    3178             : {
    3179        2266 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3180        2266 :     float8      factor = PG_GETARG_FLOAT8(1);
    3181             :     double      month_remainder_days,
    3182             :                 sec_remainder,
    3183             :                 result_double;
    3184        2266 :     int32       orig_month = span->month,
    3185        2266 :                 orig_day = span->day;
    3186             :     Interval   *result;
    3187             : 
    3188        2266 :     result = (Interval *) palloc(sizeof(Interval));
    3189             : 
    3190        2266 :     result_double = span->month * factor;
    3191        2266 :     if (isnan(result_double) ||
    3192        2266 :         result_double > INT_MAX || result_double < INT_MIN)
    3193           0 :         ereport(ERROR,
    3194             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3195             :                  errmsg("interval out of range")));
    3196        2266 :     result->month = (int32) result_double;
    3197             : 
    3198        2266 :     result_double = span->day * factor;
    3199        2266 :     if (isnan(result_double) ||
    3200        2266 :         result_double > INT_MAX || result_double < INT_MIN)
    3201           0 :         ereport(ERROR,
    3202             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3203             :                  errmsg("interval out of range")));
    3204        2266 :     result->day = (int32) result_double;
    3205             : 
    3206             :     /*
    3207             :      * The above correctly handles the whole-number part of the month and day
    3208             :      * products, but we have to do something with any fractional part
    3209             :      * resulting when the factor is non-integral.  We cascade the fractions
    3210             :      * down to lower units using the conversion factors DAYS_PER_MONTH and
    3211             :      * SECS_PER_DAY.  Note we do NOT cascade up, since we are not forced to do
    3212             :      * so by the representation.  The user can choose to cascade up later,
    3213             :      * using justify_hours and/or justify_days.
    3214             :      */
    3215             : 
    3216             :     /*
    3217             :      * Fractional months full days into days.
    3218             :      *
    3219             :      * Floating point calculation are inherently imprecise, so these
    3220             :      * calculations are crafted to produce the most reliable result possible.
    3221             :      * TSROUND() is needed to more accurately produce whole numbers where
    3222             :      * appropriate.
    3223             :      */
    3224        2266 :     month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
    3225        2266 :     month_remainder_days = TSROUND(month_remainder_days);
    3226        4532 :     sec_remainder = (orig_day * factor - result->day +
    3227        2266 :                      month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
    3228        2266 :     sec_remainder = TSROUND(sec_remainder);
    3229             : 
    3230             :     /*
    3231             :      * Might have 24:00:00 hours due to rounding, or >24 hours because of time
    3232             :      * cascade from months and days.  It might still be >24 if the combination
    3233             :      * of cascade and the seconds factor operation itself.
    3234             :      */
    3235        2266 :     if (Abs(sec_remainder) >= SECS_PER_DAY)
    3236             :     {
    3237           0 :         result->day += (int) (sec_remainder / SECS_PER_DAY);
    3238           0 :         sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
    3239             :     }
    3240             : 
    3241             :     /* cascade units down */
    3242        2266 :     result->day += (int32) month_remainder_days;
    3243        2266 :     result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
    3244        2266 :     if (result_double > PG_INT64_MAX || result_double < PG_INT64_MIN)
    3245           0 :         ereport(ERROR,
    3246             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3247             :                  errmsg("interval out of range")));
    3248        2266 :     result->time = (int64) result_double;
    3249             : 
    3250        2266 :     PG_RETURN_INTERVAL_P(result);
    3251             : }
    3252             : 
    3253             : Datum
    3254        2202 : mul_d_interval(PG_FUNCTION_ARGS)
    3255             : {
    3256             :     /* Args are float8 and Interval *, but leave them as generic Datum */
    3257        2202 :     Datum       factor = PG_GETARG_DATUM(0);
    3258        2202 :     Datum       span = PG_GETARG_DATUM(1);
    3259             : 
    3260        2202 :     return DirectFunctionCall2(interval_mul, span, factor);
    3261             : }
    3262             : 
    3263             : Datum
    3264          76 : interval_div(PG_FUNCTION_ARGS)
    3265             : {
    3266          76 :     Interval   *span = PG_GETARG_INTERVAL_P(0);
    3267          76 :     float8      factor = PG_GETARG_FLOAT8(1);
    3268             :     double      month_remainder_days,
    3269             :                 sec_remainder;
    3270          76 :     int32       orig_month = span->month,
    3271          76 :                 orig_day = span->day;
    3272             :     Interval   *result;
    3273             : 
    3274          76 :     result = (Interval *) palloc(sizeof(Interval));
    3275             : 
    3276          76 :     if (factor == 0.0)
    3277           0 :         ereport(ERROR,
    3278             :                 (errcode(ERRCODE_DIVISION_BY_ZERO),
    3279             :                  errmsg("division by zero")));
    3280             : 
    3281          76 :     result->month = (int32) (span->month / factor);
    3282          76 :     result->day = (int32) (span->day / factor);
    3283             : 
    3284             :     /*
    3285             :      * Fractional months full days into days.  See comment in interval_mul().
    3286             :      */
    3287          76 :     month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
    3288          76 :     month_remainder_days = TSROUND(month_remainder_days);
    3289         152 :     sec_remainder = (orig_day / factor - result->day +
    3290          76 :                      month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
    3291          76 :     sec_remainder = TSROUND(sec_remainder);
    3292          76 :     if (Abs(sec_remainder) >= SECS_PER_DAY)
    3293             :     {
    3294           4 :         result->day += (int) (sec_remainder / SECS_PER_DAY);
    3295           4 :         sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
    3296             :     }
    3297             : 
    3298             :     /* cascade units down */
    3299          76 :     result->day += (int32) month_remainder_days;
    3300          76 :     result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
    3301             : 
    3302          76 :     PG_RETURN_INTERVAL_P(result);
    3303             : }
    3304             : 
    3305             : 
    3306             : /*
    3307             :  * in_range support functions for timestamps and intervals.
    3308             :  *
    3309             :  * Per SQL spec, we support these with interval as the offset type.
    3310             :  * The spec's restriction that the offset not be negative is a bit hard to
    3311             :  * decipher for intervals, but we choose to interpret it the same as our
    3312             :  * interval comparison operators would.
    3313             :  */
    3314             : 
    3315             : Datum
    3316         280 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
    3317             : {
    3318         280 :     TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
    3319         280 :     TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
    3320         280 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3321         280 :     bool        sub = PG_GETARG_BOOL(3);
    3322         280 :     bool        less = PG_GETARG_BOOL(4);
    3323             :     TimestampTz sum;
    3324             : 
    3325         280 :     if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
    3326           0 :         ereport(ERROR,
    3327             :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3328             :                  errmsg("invalid preceding or following size in window function")));
    3329             : 
    3330             :     /* We don't currently bother to avoid overflow hazards here */
    3331         280 :     if (sub)
    3332         140 :         sum = DatumGetTimestampTz(DirectFunctionCall2(timestamptz_mi_interval,
    3333             :                                                       TimestampTzGetDatum(base),
    3334             :                                                       IntervalPGetDatum(offset)));
    3335             :     else
    3336         140 :         sum = DatumGetTimestampTz(DirectFunctionCall2(timestamptz_pl_interval,
    3337             :                                                       TimestampTzGetDatum(base),
    3338             :                                                       IntervalPGetDatum(offset)));
    3339             : 
    3340         280 :     if (less)
    3341         140 :         PG_RETURN_BOOL(val <= sum);
    3342             :     else
    3343         140 :         PG_RETURN_BOOL(val >= sum);
    3344             : }
    3345             : 
    3346             : Datum
    3347        1172 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
    3348             : {
    3349        1172 :     Timestamp   val = PG_GETARG_TIMESTAMP(0);
    3350        1172 :     Timestamp   base = PG_GETARG_TIMESTAMP(1);
    3351        1172 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3352        1172 :     bool        sub = PG_GETARG_BOOL(3);
    3353        1172 :     bool        less = PG_GETARG_BOOL(4);
    3354             :     Timestamp   sum;
    3355             : 
    3356        1172 :     if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
    3357           4 :         ereport(ERROR,
    3358             :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3359             :                  errmsg("invalid preceding or following size in window function")));
    3360             : 
    3361             :     /* We don't currently bother to avoid overflow hazards here */
    3362        1168 :     if (sub)
    3363         508 :         sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
    3364             :                                                     TimestampGetDatum(base),
    3365             :                                                     IntervalPGetDatum(offset)));
    3366             :     else
    3367         660 :         sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
    3368             :                                                     TimestampGetDatum(base),
    3369             :                                                     IntervalPGetDatum(offset)));
    3370             : 
    3371        1168 :     if (less)
    3372         712 :         PG_RETURN_BOOL(val <= sum);
    3373             :     else
    3374         456 :         PG_RETURN_BOOL(val >= sum);
    3375             : }
    3376             : 
    3377             : Datum
    3378         288 : in_range_interval_interval(PG_FUNCTION_ARGS)
    3379             : {
    3380         288 :     Interval   *val = PG_GETARG_INTERVAL_P(0);
    3381         288 :     Interval   *base = PG_GETARG_INTERVAL_P(1);
    3382         288 :     Interval   *offset = PG_GETARG_INTERVAL_P(2);
    3383         288 :     bool        sub = PG_GETARG_BOOL(3);
    3384         288 :     bool        less = PG_GETARG_BOOL(4);
    3385             :     Interval   *sum;
    3386             : 
    3387         288 :     if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
    3388           0 :         ereport(ERROR,
    3389             :                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    3390             :                  errmsg("invalid preceding or following size in window function")));
    3391             : 
    3392             :     /* We don't currently bother to avoid overflow hazards here */
    3393         288 :     if (sub)
    3394         144 :         sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
    3395             :                                                     IntervalPGetDatum(base),
    3396             :                                                     IntervalPGetDatum(offset)));
    3397             :     else
    3398         144 :         sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
    3399             :                                                     IntervalPGetDatum(base),
    3400             :                                                     IntervalPGetDatum(offset)));
    3401             : 
    3402         288 :     if (less)
    3403         144 :         PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
    3404             :     else
    3405         144 :         PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
    3406             : }
    3407             : 
    3408             : 
    3409             : /*
    3410             :  * interval_accum, interval_accum_inv, and interval_avg implement the
    3411             :  * AVG(interval) aggregate.
    3412             :  *
    3413             :  * The transition datatype for this aggregate is a 2-element array of
    3414             :  * intervals, where the first is the running sum and the second contains
    3415             :  * the number of values so far in its 'time' field.  This is a bit ugly
    3416             :  * but it beats inventing a specialized datatype for the purpose.
    3417             :  */
    3418             : 
    3419             : Datum
    3420          48 : interval_accum(PG_FUNCTION_ARGS)
    3421             : {
    3422          48 :     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3423          48 :     Interval   *newval = PG_GETARG_INTERVAL_P(1);
    3424             :     Datum      *transdatums;
    3425             :     int         ndatums;
    3426             :     Interval    sumX,
    3427             :                 N;
    3428             :     Interval   *newsum;
    3429             :     ArrayType  *result;
    3430             : 
    3431          48 :     deconstruct_array(transarray,
    3432             :                       INTERVALOID, sizeof(Interval), false, 'd',
    3433             :                       &transdatums, NULL, &ndatums);
    3434          48 :     if (ndatums != 2)
    3435           0 :         elog(ERROR, "expected 2-element interval array");
    3436             : 
    3437          48 :     sumX = *(DatumGetIntervalP(transdatums[0]));
    3438          48 :     N = *(DatumGetIntervalP(transdatums[1]));
    3439             : 
    3440          48 :     newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
    3441             :                                                    IntervalPGetDatum(&sumX),
    3442             :                                                    IntervalPGetDatum(newval)));
    3443          48 :     N.time += 1;
    3444             : 
    3445          48 :     transdatums[0] = IntervalPGetDatum(newsum);
    3446          48 :     transdatums[1] = IntervalPGetDatum(&N);
    3447             : 
    3448          48 :     result = construct_array(transdatums, 2,
    3449             :                              INTERVALOID, sizeof(Interval), false, 'd');
    3450             : 
    3451          48 :     PG_RETURN_ARRAYTYPE_P(result);
    3452             : }
    3453             : 
    3454             : Datum
    3455           0 : interval_combine(PG_FUNCTION_ARGS)
    3456             : {
    3457           0 :     ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
    3458           0 :     ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
    3459             :     Datum      *transdatums1;
    3460             :     Datum      *transdatums2;
    3461             :     int         ndatums1;
    3462             :     int         ndatums2;
    3463             :     Interval    sum1,
    3464             :                 N1;
    3465             :     Interval    sum2,
    3466             :                 N2;
    3467             : 
    3468             :     Interval   *newsum;
    3469             :     ArrayType  *result;
    3470             : 
    3471           0 :     deconstruct_array(transarray1,
    3472             :                       INTERVALOID, sizeof(Interval), false, 'd',
    3473             :                       &transdatums1, NULL, &ndatums1);
    3474           0 :     if (ndatums1 != 2)
    3475           0 :         elog(ERROR, "expected 2-element interval array");
    3476             : 
    3477           0 :     sum1 = *(DatumGetIntervalP(transdatums1[0]));
    3478           0 :     N1 = *(DatumGetIntervalP(transdatums1[1]));
    3479             : 
    3480           0 :     deconstruct_array(transarray2,
    3481             :                       INTERVALOID, sizeof(Interval), false, 'd',
    3482             :                       &transdatums2, NULL, &ndatums2);
    3483           0 :     if (ndatums2 != 2)
    3484           0 :         elog(ERROR, "expected 2-element interval array");
    3485             : 
    3486           0 :     sum2 = *(DatumGetIntervalP(transdatums2[0]));
    3487           0 :     N2 = *(DatumGetIntervalP(transdatums2[1]));
    3488             : 
    3489           0 :     newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
    3490             :                                                    IntervalPGetDatum(&sum1),
    3491             :                                                    IntervalPGetDatum(&sum2)));
    3492           0 :     N1.time += N2.time;
    3493             : 
    3494           0 :     transdatums1[0] = IntervalPGetDatum(newsum);
    3495           0 :     transdatums1[1] = IntervalPGetDatum(&N1);
    3496             : 
    3497           0 :     result = construct_array(transdatums1, 2,
    3498             :                              INTERVALOID, sizeof(Interval), false, 'd');
    3499             : 
    3500           0 :     PG_RETURN_ARRAYTYPE_P(result);
    3501             : }
    3502             : 
    3503             : Datum
    3504           4 : interval_accum_inv(PG_FUNCTION_ARGS)
    3505             : {
    3506           4 :     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3507           4 :     Interval   *newval = PG_GETARG_INTERVAL_P(1);
    3508             :     Datum      *transdatums;
    3509             :     int         ndatums;
    3510             :     Interval    sumX,
    3511             :                 N;
    3512             :     Interval   *newsum;
    3513             :     ArrayType  *result;
    3514             : 
    3515           4 :     deconstruct_array(transarray,
    3516             :                       INTERVALOID, sizeof(Interval), false, 'd',
    3517             :                       &transdatums, NULL, &ndatums);
    3518           4 :     if (ndatums != 2)
    3519           0 :         elog(ERROR, "expected 2-element interval array");
    3520             : 
    3521           4 :     sumX = *(DatumGetIntervalP(transdatums[0]));
    3522           4 :     N = *(DatumGetIntervalP(transdatums[1]));
    3523             : 
    3524           4 :     newsum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
    3525             :                                                    IntervalPGetDatum(&sumX),
    3526             :                                                    IntervalPGetDatum(newval)));
    3527           4 :     N.time -= 1;
    3528             : 
    3529           4 :     transdatums[0] = IntervalPGetDatum(newsum);
    3530           4 :     transdatums[1] = IntervalPGetDatum(&N);
    3531             : 
    3532           4 :     result = construct_array(transdatums, 2,
    3533             :                              INTERVALOID, sizeof(Interval), false, 'd');
    3534             : 
    3535           4 :     PG_RETURN_ARRAYTYPE_P(result);
    3536             : }
    3537             : 
    3538             : Datum
    3539          20 : interval_avg(PG_FUNCTION_ARGS)
    3540             : {
    3541          20 :     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3542             :     Datum      *transdatums;
    3543             :     int         ndatums;
    3544             :     Interval    sumX,
    3545             :                 N;
    3546             : 
    3547          20 :     deconstruct_array(transarray,
    3548             :                       INTERVALOID, sizeof(Interval), false, 'd',
    3549             :                       &transdatums, NULL, &ndatums);
    3550          20 :     if (ndatums != 2)
    3551           0 :         elog(ERROR, "expected 2-element interval array");
    3552             : 
    3553          20 :     sumX = *(DatumGetIntervalP(transdatums[0]));
    3554          20 :     N = *(DatumGetIntervalP(transdatums[1]));
    3555             : 
    3556             :     /* SQL defines AVG of no values to be NULL */
    3557          20 :     if (N.time == 0)
    3558           8 :         PG_RETURN_NULL();
    3559             : 
    3560          12 :     return DirectFunctionCall2(interval_div,
    3561             :                                IntervalPGetDatum(&sumX),
    3562             :                                Float8GetDatum((double) N.time));
    3563             : }
    3564             : 
    3565             : 
    3566             : /* timestamp_age()
    3567             :  * Calculate time difference while retaining year/month fields.
    3568             :  * Note that this does not result in an accurate absolute time span
    3569             :  *  since year and month are out of context once the arithmetic
    3570             :  *  is done.
    3571             :  */
    3572             : Datum
    3573           0 : timestamp_age(PG_FUNCTION_ARGS)
    3574             : {
    3575           0 :     Timestamp   dt1 = PG_GETARG_TIMESTAMP(0);
    3576           0 :     Timestamp   dt2 = PG_GETARG_TIMESTAMP(1);
    3577             :     Interval   *result;
    3578             :     fsec_t      fsec,
    3579             :                 fsec1,
    3580             :                 fsec2;
    3581             :     struct pg_tm tt,
    3582           0 :                *tm = &tt;
    3583             :     struct pg_tm tt1,
    3584           0 :                *tm1 = &tt1;
    3585             :     struct pg_tm tt2,
    3586           0 :                *tm2 = &tt2;
    3587             : 
    3588           0 :     result = (Interval *) palloc(sizeof(Interval));
    3589             : 
    3590           0 :     if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
    3591           0 :         timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
    3592             :     {
    3593             :         /* form the symbolic difference */
    3594           0 :         fsec = fsec1 - fsec2;
    3595           0 :         tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
    3596           0 :         tm->tm_min = tm1->tm_min - tm2->tm_min;
    3597           0 :         tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
    3598           0 :         tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
    3599           0 :         tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
    3600           0 :         tm->tm_year = tm1->tm_year - tm2->tm_year;
    3601             : 
    3602             :         /* flip sign if necessary... */
    3603           0 :         if (dt1 < dt2)
    3604             :         {
    3605           0 :             fsec = -fsec;
    3606           0 :             tm->tm_sec = -tm->tm_sec;
    3607           0 :             tm->tm_min = -tm->tm_min;
    3608           0 :             tm->tm_hour = -tm->tm_hour;
    3609           0 :             tm->tm_mday = -tm->tm_mday;
    3610           0 :             tm->tm_mon = -tm->tm_mon;
    3611           0 :             tm->tm_year = -tm->tm_year;
    3612             :         }
    3613             : 
    3614             :         /* propagate any negative fields into the next higher field */
    3615           0 :         while (fsec < 0)
    3616             :         {
    3617           0 :             fsec += USECS_PER_SEC;
    3618           0 :             tm->tm_sec--;
    3619             :         }
    3620             : 
    3621           0 :         while (tm->tm_sec < 0)
    3622             :         {
    3623           0 :             tm->tm_sec += SECS_PER_MINUTE;
    3624           0 :             tm->tm_min--;
    3625             :         }
    3626             : 
    3627           0 :         while (tm->tm_min < 0)
    3628             :         {
    3629           0 :             tm->tm_min += MINS_PER_HOUR;
    3630           0 :             tm->tm_hour--;
    3631             :         }
    3632             : 
    3633           0 :         while (tm->tm_hour < 0)
    3634             :         {
    3635           0 :             tm->tm_hour += HOURS_PER_DAY;
    3636           0 :             tm->tm_mday--;
    3637             :         }
    3638             : 
    3639           0 :         while (tm->tm_mday < 0)
    3640             :         {
    3641           0 :             if (dt1 < dt2)
    3642             :             {
    3643           0 :                 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
    3644           0 :                 tm->tm_mon--;
    3645             :             }
    3646             :             else
    3647             :             {
    3648           0 :                 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
    3649           0 :                 tm->tm_mon--;
    3650             :             }
    3651             :         }
    3652             : 
    3653           0 :         while (tm->tm_mon < 0)
    3654             :         {
    3655           0 :             tm->tm_mon += MONTHS_PER_YEAR;
    3656           0 :             tm->tm_year--;
    3657             :         }
    3658             : 
    3659             :         /* recover sign if necessary... */
    3660           0 :         if (dt1 < dt2)
    3661             :         {
    3662           0 :             fsec = -fsec;
    3663           0 :             tm->tm_sec = -tm->tm_sec;
    3664           0 :             tm->tm_min = -tm->tm_min;
    3665           0 :             tm->tm_hour = -tm->tm_hour;
    3666           0 :             tm->tm_mday = -tm->tm_mday;
    3667           0 :             tm->tm_mon = -tm->tm_mon;
    3668           0 :             tm->tm_year = -tm->tm_year;
    3669             :         }
    3670             : 
    3671           0 :         if (tm2interval(tm, fsec, result) != 0)
    3672           0 :             ereport(ERROR,
    3673             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3674             :                      errmsg("interval out of range")));
    3675             :     }
    3676             :     else
    3677           0 :         ereport(ERROR,
    3678             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3679             :                  errmsg("timestamp out of range")));
    3680             : 
    3681           0 :     PG_RETURN_INTERVAL_P(result);
    3682             : }
    3683             : 
    3684             : 
    3685             : /* timestamptz_age()
    3686             :  * Calculate time difference while retaining year/month fields.
    3687             :  * Note that this does not result in an accurate absolute time span
    3688             :  *  since year and month are out of context once the arithmetic
    3689             :  *  is done.
    3690             :  */
    3691             : Datum
    3692           0 : timestamptz_age(PG_FUNCTION_ARGS)
    3693             : {
    3694           0 :     TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
    3695           0 :     TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
    3696             :     Interval   *result;
    3697             :     fsec_t      fsec,
    3698             :                 fsec1,
    3699             :                 fsec2;
    3700             :     struct pg_tm tt,
    3701           0 :                *tm = &tt;
    3702             :     struct pg_tm tt1,
    3703           0 :                *tm1 = &tt1;
    3704             :     struct pg_tm tt2,
    3705           0 :                *tm2 = &tt2;
    3706             :     int         tz1;
    3707             :     int         tz2;
    3708             : 
    3709           0 :     result = (Interval *) palloc(sizeof(Interval));
    3710             : 
    3711           0 :     if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
    3712           0 :         timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
    3713             :     {
    3714             :         /* form the symbolic difference */
    3715           0 :         fsec = fsec1 - fsec2;
    3716           0 :         tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
    3717           0 :         tm->tm_min = tm1->tm_min - tm2->tm_min;
    3718           0 :         tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
    3719           0 :         tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
    3720           0 :         tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
    3721           0 :         tm->tm_year = tm1->tm_year - tm2->tm_year;
    3722             : 
    3723             :         /* flip sign if necessary... */
    3724           0 :         if (dt1 < dt2)
    3725             :         {
    3726           0 :             fsec = -fsec;
    3727           0 :             tm->tm_sec = -tm->tm_sec;
    3728           0 :             tm->tm_min = -tm->tm_min;
    3729           0 :             tm->tm_hour = -tm->tm_hour;
    3730           0 :             tm->tm_mday = -tm->tm_mday;
    3731           0 :             tm->tm_mon = -tm->tm_mon;
    3732           0 :             tm->tm_year = -tm->tm_year;
    3733             :         }
    3734             : 
    3735             :         /* propagate any negative fields into the next higher field */
    3736           0 :         while (fsec < 0)
    3737             :         {
    3738           0 :             fsec += USECS_PER_SEC;
    3739           0 :             tm->tm_sec--;
    3740             :         }
    3741             : 
    3742           0 :         while (tm->tm_sec < 0)
    3743             :         {
    3744           0 :             tm->tm_sec += SECS_PER_MINUTE;
    3745           0 :             tm->tm_min--;
    3746             :         }
    3747             : 
    3748           0 :         while (tm->tm_min < 0)
    3749             :         {
    3750           0 :             tm->tm_min += MINS_PER_HOUR;
    3751           0 :             tm->tm_hour--;
    3752             :         }
    3753             : 
    3754           0 :         while (tm->tm_hour < 0)
    3755             :         {
    3756           0 :             tm->tm_hour += HOURS_PER_DAY;
    3757           0 :             tm->tm_mday--;
    3758             :         }
    3759             : 
    3760           0 :         while (tm->tm_mday < 0)
    3761             :         {
    3762           0 :             if (dt1 < dt2)
    3763             :             {
    3764           0 :                 tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
    3765           0 :                 tm->tm_mon--;
    3766             :             }
    3767             :             else
    3768             :             {
    3769           0 :                 tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
    3770           0 :                 tm->tm_mon--;
    3771             :             }
    3772             :         }
    3773             : 
    3774           0 :         while (tm->tm_mon < 0)
    3775             :         {
    3776           0 :             tm->tm_mon += MONTHS_PER_YEAR;
    3777           0 :             tm->tm_year--;
    3778             :         }
    3779             : 
    3780             :         /*
    3781             :          * Note: we deliberately ignore any difference between tz1 and tz2.
    3782             :          */
    3783             : 
    3784             :         /* recover sign if necessary... */
    3785           0 :         if (dt1 < dt2)
    3786             :         {
    3787           0 :             fsec = -fsec;
    3788           0 :             tm->tm_sec = -tm->tm_sec;
    3789           0 :             tm->tm_min = -tm->tm_min;
    3790           0 :             tm->tm_hour = -tm->tm_hour;
    3791           0 :             tm->tm_mday = -tm->tm_mday;
    3792           0 :             tm->tm_mon = -tm->tm_mon;
    3793           0 :             tm->tm_year = -tm->tm_year;
    3794             :         }
    3795             : 
    3796           0 :         if (tm2interval(tm, fsec, result) != 0)
    3797           0 :             ereport(ERROR,
    3798             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3799             :                      errmsg("interval out of range")));
    3800             :     }
    3801             :     else
    3802           0 :         ereport(ERROR,
    3803             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3804             :                  errmsg("timestamp out of range")));
    3805             : 
    3806           0 :     PG_RETURN_INTERVAL_P(result);
    3807             : }
    3808             : 
    3809             : 
    3810             : /*----------------------------------------------------------
    3811             :  *  Conversion operators.
    3812             :  *---------------------------------------------------------*/
    3813             : 
    3814             : 
    3815             : /* timestamp_trunc()
    3816             :  * Truncate timestamp to specified units.
    3817             :  */
    3818             : Datum
    3819          12 : timestamp_trunc(PG_FUNCTION_ARGS)
    3820             : {
    3821          12 :     text       *units = PG_GETARG_TEXT_PP(0);
    3822          12 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    3823             :     Timestamp   result;
    3824             :     int         type,
    3825             :                 val;
    3826             :     char       *lowunits;
    3827             :     fsec_t      fsec;
    3828             :     struct pg_tm tt,
    3829          12 :                *tm = &tt;
    3830             : 
    3831          12 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    3832           0 :         PG_RETURN_TIMESTAMP(timestamp);
    3833             : 
    3834          36 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    3835          36 :                                             VARSIZE_ANY_EXHDR(units),
    3836             :                                             false);
    3837             : 
    3838          12 :     type = DecodeUnits(0, lowunits, &val);
    3839             : 
    3840          12 :     if (type == UNITS)
    3841             :     {
    3842          12 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    3843           0 :             ereport(ERROR,
    3844             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3845             :                      errmsg("timestamp out of range")));
    3846             : 
    3847          12 :         switch (val)
    3848             :         {
    3849             :             case DTK_WEEK:
    3850             :                 {
    3851             :                     int         woy;
    3852             : 
    3853           4 :                     woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    3854             : 
    3855             :                     /*
    3856             :                      * If it is week 52/53 and the month is January, then the
    3857             :                      * week must belong to the previous year. Also, some
    3858             :                      * December dates belong to the next year.
    3859             :                      */
    3860           4 :                     if (woy >= 52 && tm->tm_mon == 1)
    3861           0 :                         --tm->tm_year;
    3862           4 :                     if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
    3863           0 :                         ++tm->tm_year;
    3864           4 :                     isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
    3865           4 :                     tm->tm_hour = 0;
    3866           4 :                     tm->tm_min = 0;
    3867           4 :                     tm->tm_sec = 0;
    3868           4 :                     fsec = 0;
    3869           4 :                     break;
    3870             :                 }
    3871             :             case DTK_MILLENNIUM:
    3872             :                 /* see comments in timestamptz_trunc */
    3873           4 :                 if (tm->tm_year > 0)
    3874           4 :                     tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
    3875             :                 else
    3876           0 :                     tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
    3877             :                 /* FALL THRU */
    3878             :             case DTK_CENTURY:
    3879             :                 /* see comments in timestamptz_trunc */
    3880           8 :                 if (tm->tm_year > 0)
    3881           8 :                     tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
    3882             :                 else
    3883           0 :                     tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
    3884             :                 /* FALL THRU */
    3885             :             case DTK_DECADE:
    3886             :                 /* see comments in timestamptz_trunc */
    3887           8 :                 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
    3888             :                 {
    3889           0 :                     if (tm->tm_year > 0)
    3890           0 :                         tm->tm_year = (tm->tm_year / 10) * 10;
    3891             :                     else
    3892           0 :                         tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
    3893             :                 }
    3894             :                 /* FALL THRU */
    3895             :             case DTK_YEAR:
    3896           8 :                 tm->tm_mon = 1;
    3897             :                 /* FALL THRU */
    3898             :             case DTK_QUARTER:
    3899           8 :                 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
    3900             :                 /* FALL THRU */
    3901             :             case DTK_MONTH:
    3902           8 :                 tm->tm_mday = 1;
    3903             :                 /* FALL THRU */
    3904             :             case DTK_DAY:
    3905           8 :                 tm->tm_hour = 0;
    3906             :                 /* FALL THRU */
    3907             :             case DTK_HOUR:
    3908           8 :                 tm->tm_min = 0;
    3909             :                 /* FALL THRU */
    3910             :             case DTK_MINUTE:
    3911           8 :                 tm->tm_sec = 0;
    3912             :                 /* FALL THRU */
    3913             :             case DTK_SECOND:
    3914           8 :                 fsec = 0;
    3915           8 :                 break;
    3916             : 
    3917             :             case DTK_MILLISEC:
    3918           0 :                 fsec = (fsec / 1000) * 1000;
    3919           0 :                 break;
    3920             : 
    3921             :             case DTK_MICROSEC:
    3922           0 :                 break;
    3923             : 
    3924             :             default:
    3925           0 :                 ereport(ERROR,
    3926             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3927             :                          errmsg("timestamp units \"%s\" not supported",
    3928             :                                 lowunits)));
    3929             :                 result = 0;
    3930             :         }
    3931             : 
    3932          12 :         if (tm2timestamp(tm, fsec, NULL, &result) != 0)
    3933           0 :             ereport(ERROR,
    3934             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3935             :                      errmsg("timestamp out of range")));
    3936             :     }
    3937             :     else
    3938             :     {
    3939           0 :         ereport(ERROR,
    3940             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3941             :                  errmsg("timestamp units \"%s\" not recognized",
    3942             :                         lowunits)));
    3943             :         result = 0;
    3944             :     }
    3945             : 
    3946          12 :     PG_RETURN_TIMESTAMP(result);
    3947             : }
    3948             : 
    3949             : /*
    3950             :  * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
    3951             :  *
    3952             :  * tzp identifies the zone to truncate with respect to.  We assume
    3953             :  * infinite timestamps have already been rejected.
    3954             :  */
    3955             : static TimestampTz
    3956          48 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
    3957             : {
    3958             :     TimestampTz result;
    3959             :     int         tz;
    3960             :     int         type,
    3961             :                 val;
    3962          48 :     bool        redotz = false;
    3963             :     char       *lowunits;
    3964             :     fsec_t      fsec;
    3965             :     struct pg_tm tt,
    3966          48 :                *tm = &tt;
    3967             : 
    3968         144 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    3969         144 :                                             VARSIZE_ANY_EXHDR(units),
    3970             :                                             false);
    3971             : 
    3972          48 :     type = DecodeUnits(0, lowunits, &val);
    3973             : 
    3974          48 :     if (type == UNITS)
    3975             :     {
    3976          48 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
    3977           0 :             ereport(ERROR,
    3978             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3979             :                      errmsg("timestamp out of range")));
    3980             : 
    3981          48 :         switch (val)
    3982             :         {
    3983             :             case DTK_WEEK:
    3984             :                 {
    3985             :                     int         woy;
    3986             : 
    3987           4 :                     woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    3988             : 
    3989             :                     /*
    3990             :                      * If it is week 52/53 and the month is January, then the
    3991             :                      * week must belong to the previous year. Also, some
    3992             :                      * December dates belong to the next year.
    3993             :                      */
    3994           4 :                     if (woy >= 52 && tm->tm_mon == 1)
    3995           0 :                         --tm->tm_year;
    3996           4 :                     if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
    3997           0 :                         ++tm->tm_year;
    3998           4 :                     isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
    3999           4 :                     tm->tm_hour = 0;
    4000           4 :                     tm->tm_min = 0;
    4001           4 :                     tm->tm_sec = 0;
    4002           4 :                     fsec = 0;
    4003           4 :                     redotz = true;
    4004           4 :                     break;
    4005             :                 }
    4006             :                 /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
    4007             :             case DTK_MILLENNIUM:
    4008             : 
    4009             :                 /*
    4010             :                  * truncating to the millennium? what is this supposed to
    4011             :                  * mean? let us put the first year of the millennium... i.e.
    4012             :                  * -1000, 1, 1001, 2001...
    4013             :                  */
    4014           4 :                 if (tm->tm_year > 0)
    4015           4 :                     tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
    4016             :                 else
    4017           0 :                     tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
    4018             :                 /* FALL THRU */
    4019             :             case DTK_CENTURY:
    4020             :                 /* truncating to the century? as above: -100, 1, 101... */
    4021          20 :                 if (tm->tm_year > 0)
    4022          16 :                     tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
    4023             :                 else
    4024           4 :                     tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
    4025             :                 /* FALL THRU */
    4026             :             case DTK_DECADE:
    4027             : 
    4028             :                 /*
    4029             :                  * truncating to the decade? first year of the decade. must
    4030             :                  * not be applied if year was truncated before!
    4031             :                  */
    4032          32 :                 if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
    4033             :                 {
    4034          12 :                     if (tm->tm_year > 0)
    4035           8 :                         tm->tm_year = (tm->tm_year / 10) * 10;
    4036             :                     else
    4037           4 :                         tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
    4038             :                 }
    4039             :                 /* FALL THRU */
    4040             :             case DTK_YEAR:
    4041          32 :                 tm->tm_mon = 1;
    4042             :                 /* FALL THRU */
    4043             :             case DTK_QUARTER:
    4044          32 :                 tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
    4045             :                 /* FALL THRU */
    4046             :             case DTK_MONTH:
    4047          32 :                 tm->tm_mday = 1;
    4048             :                 /* FALL THRU */
    4049             :             case DTK_DAY:
    4050          44 :                 tm->tm_hour = 0;
    4051          44 :                 redotz = true;  /* for all cases >= DAY */
    4052             :                 /* FALL THRU */
    4053             :             case DTK_HOUR:
    4054          44 :                 tm->tm_min = 0;
    4055             :                 /* FALL THRU */
    4056             :             case DTK_MINUTE:
    4057          44 :                 tm->tm_sec = 0;
    4058             :                 /* FALL THRU */
    4059             :             case DTK_SECOND:
    4060          44 :                 fsec = 0;
    4061          44 :                 break;
    4062             :             case DTK_MILLISEC:
    4063           0 :                 fsec = (fsec / 1000) * 1000;
    4064           0 :                 break;
    4065             :             case DTK_MICROSEC:
    4066           0 :                 break;
    4067             : 
    4068             :             default:
    4069           0 :                 ereport(ERROR,
    4070             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4071             :                          errmsg("timestamp with time zone units \"%s\" not "
    4072             :                                 "supported", lowunits)));
    4073             :                 result = 0;
    4074             :         }
    4075             : 
    4076          48 :         if (redotz)
    4077          48 :             tz = DetermineTimeZoneOffset(tm, tzp);
    4078             : 
    4079          48 :         if (tm2timestamp(tm, fsec, &tz, &result) != 0)
    4080           0 :             ereport(ERROR,
    4081             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4082             :                      errmsg("timestamp out of range")));
    4083             :     }
    4084             :     else
    4085             :     {
    4086           0 :         ereport(ERROR,
    4087             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4088             :                  errmsg("timestamp with time zone units \"%s\" not recognized",
    4089             :                         lowunits)));
    4090             :         result = 0;
    4091             :     }
    4092             : 
    4093          48 :     return result;
    4094             : }
    4095             : 
    4096             : /* timestamptz_trunc()
    4097             :  * Truncate timestamptz to specified units in session timezone.
    4098             :  */
    4099             : Datum
    4100          36 : timestamptz_trunc(PG_FUNCTION_ARGS)
    4101             : {
    4102          36 :     text       *units = PG_GETARG_TEXT_PP(0);
    4103          36 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    4104             :     TimestampTz result;
    4105             : 
    4106          36 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4107           0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    4108             : 
    4109          36 :     result = timestamptz_trunc_internal(units, timestamp, session_timezone);
    4110             : 
    4111          36 :     PG_RETURN_TIMESTAMPTZ(result);
    4112             : }
    4113             : 
    4114             : /* timestamptz_trunc_zone()
    4115             :  * Truncate timestamptz to specified units in specified timezone.
    4116             :  */
    4117             : Datum
    4118          12 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
    4119             : {
    4120          12 :     text       *units = PG_GETARG_TEXT_PP(0);
    4121          12 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    4122          12 :     text       *zone = PG_GETARG_TEXT_PP(2);
    4123             :     TimestampTz result;
    4124             :     char        tzname[TZ_STRLEN_MAX + 1];
    4125             :     char       *lowzone;
    4126             :     int         type,
    4127             :                 val;
    4128             :     pg_tz      *tzp;
    4129             : 
    4130             :     /*
    4131             :      * timestamptz_zone() doesn't look up the zone for infinite inputs, so we
    4132             :      * don't do so here either.
    4133             :      */
    4134          12 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4135           0 :         PG_RETURN_TIMESTAMP(timestamp);
    4136             : 
    4137             :     /*
    4138             :      * Look up the requested timezone (see notes in timestamptz_zone()).
    4139             :      */
    4140          12 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    4141             : 
    4142             :     /* DecodeTimezoneAbbrev requires lowercase input */
    4143          12 :     lowzone = downcase_truncate_identifier(tzname,
    4144          12 :                                            strlen(tzname),
    4145             :                                            false);
    4146             : 
    4147          12 :     type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
    4148             : 
    4149          12 :     if (type == TZ || type == DTZ)
    4150             :     {
    4151             :         /* fixed-offset abbreviation, get a pg_tz descriptor for that */
    4152           4 :         tzp = pg_tzset_offset(-val);
    4153             :     }
    4154           8 :     else if (type == DYNTZ)
    4155             :     {
    4156             :         /* dynamic-offset abbreviation, use its referenced timezone */
    4157             :     }
    4158             :     else
    4159             :     {
    4160             :         /* try it as a full zone name */
    4161           4 :         tzp = pg_tzset(tzname);
    4162           4 :         if (!tzp)
    4163           0 :             ereport(ERROR,
    4164             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4165             :                      errmsg("time zone \"%s\" not recognized", tzname)));
    4166             :     }
    4167             : 
    4168          12 :     result = timestamptz_trunc_internal(units, timestamp, tzp);
    4169             : 
    4170          12 :     PG_RETURN_TIMESTAMPTZ(result);
    4171             : }
    4172             : 
    4173             : /* interval_trunc()
    4174             :  * Extract specified field from interval.
    4175             :  */
    4176             : Datum
    4177           0 : interval_trunc(PG_FUNCTION_ARGS)
    4178             : {
    4179           0 :     text       *units = PG_GETARG_TEXT_PP(0);
    4180           0 :     Interval   *interval = PG_GETARG_INTERVAL_P(1);
    4181             :     Interval   *result;
    4182             :     int         type,
    4183             :                 val;
    4184             :     char       *lowunits;
    4185             :     fsec_t      fsec;
    4186             :     struct pg_tm tt,
    4187           0 :                *tm = &tt;
    4188             : 
    4189           0 :     result = (Interval *) palloc(sizeof(Interval));
    4190             : 
    4191           0 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4192           0 :                                             VARSIZE_ANY_EXHDR(units),
    4193             :                                             false);
    4194             : 
    4195           0 :     type = DecodeUnits(0, lowunits, &val);
    4196             : 
    4197           0 :     if (type == UNITS)
    4198             :     {
    4199           0 :         if (interval2tm(*interval, tm, &fsec) == 0)
    4200             :         {
    4201           0 :             switch (val)
    4202             :             {
    4203             :                 case DTK_MILLENNIUM:
    4204             :                     /* caution: C division may have negative remainder */
    4205           0 :                     tm->tm_year = (tm->tm_year / 1000) * 1000;
    4206             :                     /* FALL THRU */
    4207             :                 case DTK_CENTURY:
    4208             :                     /* caution: C division may have negative remainder */
    4209           0 :                     tm->tm_year = (tm->tm_year / 100) * 100;
    4210             :                     /* FALL THRU */
    4211             :                 case DTK_DECADE:
    4212             :                     /* caution: C division may have negative remainder */
    4213           0 :                     tm->tm_year = (tm->tm_year / 10) * 10;
    4214             :                     /* FALL THRU */
    4215             :                 case DTK_YEAR:
    4216           0 :                     tm->tm_mon = 0;
    4217             :                     /* FALL THRU */
    4218             :                 case DTK_QUARTER:
    4219           0 :                     tm->tm_mon = 3 * (tm->tm_mon / 3);
    4220             :                     /* FALL THRU */
    4221             :                 case DTK_MONTH:
    4222           0 :                     tm->tm_mday = 0;
    4223             :                     /* FALL THRU */
    4224             :                 case DTK_DAY:
    4225           0 :                     tm->tm_hour = 0;
    4226             :                     /* FALL THRU */
    4227             :                 case DTK_HOUR:
    4228           0 :                     tm->tm_min = 0;
    4229             :                     /* FALL THRU */
    4230             :                 case DTK_MINUTE:
    4231           0 :                     tm->tm_sec = 0;
    4232             :                     /* FALL THRU */
    4233             :                 case DTK_SECOND:
    4234           0 :                     fsec = 0;
    4235           0 :                     break;
    4236             :                 case DTK_MILLISEC:
    4237           0 :                     fsec = (fsec / 1000) * 1000;
    4238           0 :                     break;
    4239             :                 case DTK_MICROSEC:
    4240           0 :                     break;
    4241             : 
    4242             :                 default:
    4243           0 :                     if (val == DTK_WEEK)
    4244           0 :                         ereport(ERROR,
    4245             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4246             :                                  errmsg("interval units \"%s\" not supported "
    4247             :                                         "because months usually have fractional weeks",
    4248             :                                         lowunits)));
    4249             :                     else
    4250           0 :                         ereport(ERROR,
    4251             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4252             :                                  errmsg("interval units \"%s\" not supported",
    4253             :                                         lowunits)));
    4254             :             }
    4255             : 
    4256           0 :             if (tm2interval(tm, fsec, result) != 0)
    4257           0 :                 ereport(ERROR,
    4258             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4259             :                          errmsg("interval out of range")));
    4260             :         }
    4261             :         else
    4262           0 :             elog(ERROR, "could not convert interval to tm");
    4263             :     }
    4264             :     else
    4265             :     {
    4266           0 :         ereport(ERROR,
    4267             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4268             :                  errmsg("interval units \"%s\" not recognized",
    4269             :                         lowunits)));
    4270             :     }
    4271             : 
    4272           0 :     PG_RETURN_INTERVAL_P(result);
    4273             : }
    4274             : 
    4275             : /* isoweek2j()
    4276             :  *
    4277             :  *  Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
    4278             :  *  Julian days are used to convert between ISO week dates and Gregorian dates.
    4279             :  */
    4280             : int
    4281        1044 : isoweek2j(int year, int week)
    4282             : {
    4283             :     int         day0,
    4284             :                 day4;
    4285             : 
    4286             :     /* fourth day of current year */
    4287        1044 :     day4 = date2j(year, 1, 4);
    4288             : 
    4289             :     /* day0 == offset to first day of week (Monday) */
    4290        1044 :     day0 = j2day(day4 - 1);
    4291             : 
    4292        1044 :     return ((week - 1) * 7) + (day4 - day0);
    4293             : }
    4294             : 
    4295             : /* isoweek2date()
    4296             :  * Convert ISO week of year number to date.
    4297             :  * The year field must be specified with the ISO year!
    4298             :  * karel 2000/08/07
    4299             :  */
    4300             : void
    4301           8 : isoweek2date(int woy, int *year, int *mon, int *mday)
    4302             : {
    4303           8 :     j2date(isoweek2j(*year, woy), year, mon, mday);
    4304           8 : }
    4305             : 
    4306             : /* isoweekdate2date()
    4307             :  *
    4308             :  *  Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
    4309             :  *  Gregorian day of week sent so weekday strings can be supplied.
    4310             :  *  Populates year, mon, and mday with the correct Gregorian values.
    4311             :  *  year must be passed in as the ISO year.
    4312             :  */
    4313             : void
    4314          16 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
    4315             : {
    4316             :     int         jday;
    4317             : 
    4318          16 :     jday = isoweek2j(*year, isoweek);
    4319             :     /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
    4320          16 :     if (wday > 1)
    4321           0 :         jday += wday - 2;
    4322             :     else
    4323          16 :         jday += 6;
    4324          16 :     j2date(jday, year, mon, mday);
    4325          16 : }
    4326             : 
    4327             : /* date2isoweek()
    4328             :  *
    4329             :  *  Returns ISO week number of year.
    4330             :  */
    4331             : int
    4332        1468 : date2isoweek(int year, int mon, int mday)
    4333             : {
    4334             :     float8      result;
    4335             :     int         day0,
    4336             :                 day4,
    4337             :                 dayn;
    4338             : 
    4339             :     /* current day */
    4340        1468 :     dayn = date2j(year, mon, mday);
    4341             : 
    4342             :     /* fourth day of current year */
    4343        1468 :     day4 = date2j(year, 1, 4);
    4344             : 
    4345             :     /* day0 == offset to first day of week (Monday) */
    4346        1468 :     day0 = j2day(day4 - 1);
    4347             : 
    4348             :     /*
    4349             :      * We need the first week containing a Thursday, otherwise this day falls
    4350             :      * into the previous year for purposes of counting weeks
    4351             :      */
    4352        1468 :     if (dayn < day4 - day0)
    4353             :     {
    4354          24 :         day4 = date2j(year - 1, 1, 4);
    4355             : 
    4356             :         /* day0 == offset to first day of week (Monday) */
    4357          24 :         day0 = j2day(day4 - 1);
    4358             :     }
    4359             : 
    4360        1468 :     result = (dayn - (day4 - day0)) / 7 + 1;
    4361             : 
    4362             :     /*
    4363             :      * Sometimes the last few days in a year will fall into the first week of
    4364             :      * the next year, so check for this.
    4365             :      */
    4366        1468 :     if (result >= 52)
    4367             :     {
    4368         180 :         day4 = date2j(year + 1, 1, 4);
    4369             : 
    4370             :         /* day0 == offset to first day of week (Monday) */
    4371         180 :         day0 = j2day(day4 - 1);
    4372             : 
    4373         180 :         if (dayn >= day4 - day0)
    4374         108 :             result = (dayn - (day4 - day0)) / 7 + 1;
    4375             :     }
    4376             : 
    4377        1468 :     return (int) result;
    4378             : }
    4379             : 
    4380             : 
    4381             : /* date2isoyear()
    4382             :  *
    4383             :  *  Returns ISO 8601 year number.
    4384             :  */
    4385             : int
    4386        9588 : date2isoyear(int year, int mon, int mday)
    4387             : {
    4388             :     float8      result;
    4389             :     int         day0,
    4390             :                 day4,
    4391             :                 dayn;
    4392             : 
    4393             :     /* current day */
    4394        9588 :     dayn = date2j(year, mon, mday);
    4395             : 
    4396             :     /* fourth day of current year */
    4397        9588 :     day4 = date2j(year, 1, 4);
    4398             : 
    4399             :     /* day0 == offset to first day of week (Monday) */
    4400        9588 :     day0 = j2day(day4 - 1);
    4401             : 
    4402             :     /*
    4403             :      * We need the first week containing a Thursday, otherwise this day falls
    4404             :      * into the previous year for purposes of counting weeks
    4405             :      */
    4406        9588 :     if (dayn < day4 - day0)
    4407             :     {
    4408         152 :         day4 = date2j(year - 1, 1, 4);
    4409             : 
    4410             :         /* day0 == offset to first day of week (Monday) */
    4411         152 :         day0 = j2day(day4 - 1);
    4412             : 
    4413         152 :         year--;
    4414             :     }
    4415             : 
    4416        9588 :     result = (dayn - (day4 - day0)) / 7 + 1;
    4417             : 
    4418             :     /*
    4419             :      * Sometimes the last few days in a year will fall into the first week of
    4420             :      * the next year, so check for this.
    4421             :      */
    4422        9588 :     if (result >= 52)
    4423             :     {
    4424        1140 :         day4 = date2j(year + 1, 1, 4);
    4425             : 
    4426             :         /* day0 == offset to first day of week (Monday) */
    4427        1140 :         day0 = j2day(day4 - 1);
    4428             : 
    4429        1140 :         if (dayn >= day4 - day0)
    4430         684 :             year++;
    4431             :     }
    4432             : 
    4433        9588 :     return year;
    4434             : }
    4435             : 
    4436             : 
    4437             : /* date2isoyearday()
    4438             :  *
    4439             :  *  Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
    4440             :  *  Possible return values are 1 through 371 (364 in non-leap years).
    4441             :  */
    4442             : int
    4443        1016 : date2isoyearday(int year, int mon, int mday)
    4444             : {
    4445        1016 :     return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
    4446             : }
    4447             : 
    4448             : /*
    4449             :  * NonFiniteTimestampTzPart
    4450             :  *
    4451             :  *  Used by timestamp_part and timestamptz_part when extracting from infinite
    4452             :  *  timestamp[tz].  Returns +/-Infinity if that is the appropriate result,
    4453             :  *  otherwise returns zero (which should be taken as meaning to return NULL).
    4454             :  *
    4455             :  *  Errors thrown here for invalid units should exactly match those that
    4456             :  *  would be thrown in the calling functions, else there will be unexpected
    4457             :  *  discrepancies between finite- and infinite-input cases.
    4458             :  */
    4459             : static float8
    4460         144 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
    4461             :                          bool isNegative, bool isTz)
    4462             : {
    4463         144 :     if ((type != UNITS) && (type != RESERV))
    4464             :     {
    4465           4 :         if (isTz)
    4466           0 :             ereport(ERROR,
    4467             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4468             :                      errmsg("timestamp with time zone units \"%s\" not recognized",
    4469             :                             lowunits)));
    4470             :         else
    4471           4 :             ereport(ERROR,
    4472             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4473             :                      errmsg("timestamp units \"%s\" not recognized",
    4474             :                             lowunits)));
    4475             :     }
    4476             : 
    4477         140 :     switch (unit)
    4478             :     {
    4479             :             /* Oscillating units */
    4480             :         case DTK_MICROSEC:
    4481             :         case DTK_MILLISEC:
    4482             :         case DTK_SECOND:
    4483             :         case DTK_MINUTE:
    4484             :         case DTK_HOUR:
    4485             :         case DTK_DAY:
    4486             :         case DTK_MONTH:
    4487             :         case DTK_QUARTER:
    4488             :         case DTK_WEEK:
    4489             :         case DTK_DOW:
    4490             :         case DTK_ISODOW:
    4491             :         case DTK_DOY:
    4492             :         case DTK_TZ:
    4493             :         case DTK_TZ_MINUTE:
    4494             :         case DTK_TZ_HOUR:
    4495          84 :             return 0.0;
    4496             : 
    4497             :             /* Monotonically-increasing units */
    4498             :         case DTK_YEAR:
    4499             :         case DTK_DECADE:
    4500             :         case DTK_CENTURY:
    4501             :         case DTK_MILLENNIUM:
    4502             :         case DTK_JULIAN:
    4503             :         case DTK_ISOYEAR:
    4504             :         case DTK_EPOCH:
    4505          52 :             if (isNegative)
    4506          12 :                 return -get_float8_infinity();
    4507             :             else
    4508          40 :                 return get_float8_infinity();
    4509             : 
    4510             :         default:
    4511           4 :             if (isTz)
    4512           0 :                 ereport(ERROR,
    4513             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4514             :                          errmsg("timestamp with time zone units \"%s\" not supported",
    4515             :                                 lowunits)));
    4516             :             else
    4517           4 :                 ereport(ERROR,
    4518             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4519             :                          errmsg("timestamp units \"%s\" not supported",
    4520             :                                 lowunits)));
    4521             :             return 0.0;         /* keep compiler quiet */
    4522             :     }
    4523             : }
    4524             : 
    4525             : /* timestamp_part()
    4526             :  * Extract specified field from timestamp.
    4527             :  */
    4528             : Datum
    4529        3048 : timestamp_part(PG_FUNCTION_ARGS)
    4530             : {
    4531        3048 :     text       *units = PG_GETARG_TEXT_PP(0);
    4532        3048 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    4533             :     float8      result;
    4534             :     Timestamp   epoch;
    4535             :     int         type,
    4536             :                 val;
    4537             :     char       *lowunits;
    4538             :     fsec_t      fsec;
    4539             :     struct pg_tm tt,
    4540        3048 :                *tm = &tt;
    4541             : 
    4542        9144 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4543        9144 :                                             VARSIZE_ANY_EXHDR(units),
    4544             :                                             false);
    4545             : 
    4546        3048 :     type = DecodeUnits(0, lowunits, &val);
    4547        3048 :     if (type == UNKNOWN_FIELD)
    4548         492 :         type = DecodeSpecial(0, lowunits, &val);
    4549             : 
    4550        3048 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4551             :     {
    4552         128 :         result = NonFiniteTimestampTzPart(type, val, lowunits,
    4553             :                                           TIMESTAMP_IS_NOBEGIN(timestamp),
    4554             :                                           false);
    4555         120 :         if (result)
    4556          44 :             PG_RETURN_FLOAT8(result);
    4557             :         else
    4558          76 :             PG_RETURN_NULL();
    4559             :     }
    4560             : 
    4561        2920 :     if (type == UNITS)
    4562             :     {
    4563        2912 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    4564           0 :             ereport(ERROR,
    4565             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4566             :                      errmsg("timestamp out of range")));
    4567             : 
    4568        2912 :         switch (val)
    4569             :         {
    4570             :             case DTK_MICROSEC:
    4571         220 :                 result = tm->tm_sec * 1000000.0 + fsec;
    4572         220 :                 break;
    4573             : 
    4574             :             case DTK_MILLISEC:
    4575         220 :                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
    4576         220 :                 break;
    4577             : 
    4578             :             case DTK_SECOND:
    4579         220 :                 result = tm->tm_sec + fsec / 1000000.0;
    4580         220 :                 break;
    4581             : 
    4582             :             case DTK_MINUTE:
    4583         220 :                 result = tm->tm_min;
    4584         220 :                 break;
    4585             : 
    4586             :             case DTK_HOUR:
    4587         220 :                 result = tm->tm_hour;
    4588         220 :                 break;
    4589             : 
    4590             :             case DTK_DAY:
    4591         220 :                 result = tm->tm_mday;
    4592         220 :                 break;
    4593             : 
    4594             :             case DTK_MONTH:
    4595         276 :                 result = tm->tm_mon;
    4596         276 :                 break;
    4597             : 
    4598             :             case DTK_QUARTER:
    4599         220 :                 result = (tm->tm_mon - 1) / 3 + 1;
    4600         220 :                 break;
    4601             : 
    4602             :             case DTK_WEEK:
    4603         220 :                 result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4604         220 :                 break;
    4605             : 
    4606             :             case DTK_YEAR:
    4607         336 :                 if (tm->tm_year > 0)
    4608         336 :                     result = tm->tm_year;
    4609             :                 else
    4610             :                     /* there is no year 0, just 1 BC and 1 AD */
    4611           0 :                     result = tm->tm_year - 1;
    4612         336 :                 break;
    4613             : 
    4614             :             case DTK_DECADE:
    4615             : 
    4616             :                 /*
    4617             :                  * what is a decade wrt dates? let us assume that decade 199
    4618             :                  * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
    4619             :                  * is 11 BC thru 2 BC...
    4620             :                  */
    4621          28 :                 if (tm->tm_year >= 0)
    4622          16 :                     result = tm->tm_year / 10;
    4623             :                 else
    4624          12 :                     result = -((8 - (tm->tm_year - 1)) / 10);
    4625          28 :                 break;
    4626             : 
    4627             :             case DTK_CENTURY:
    4628             : 
    4629             :                 /* ----
    4630             :                  * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
    4631             :                  * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
    4632             :                  * there is no number 0 century.
    4633             :                  * ----
    4634             :                  */
    4635          44 :                 if (tm->tm_year > 0)
    4636          32 :                     result = (tm->tm_year + 99) / 100;
    4637             :                 else
    4638             :                     /* caution: C division may have negative remainder */
    4639          12 :                     result = -((99 - (tm->tm_year - 1)) / 100);
    4640          44 :                 break;
    4641             : 
    4642             :             case DTK_MILLENNIUM:
    4643             :                 /* see comments above. */
    4644          28 :                 if (tm->tm_year > 0)
    4645          24 :                     result = (tm->tm_year + 999) / 1000;
    4646             :                 else
    4647           4 :                     result = -((999 - (tm->tm_year - 1)) / 1000);
    4648          28 :                 break;
    4649             : 
    4650             :             case DTK_JULIAN:
    4651           0 :                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4652           0 :                 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
    4653           0 :                            tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
    4654           0 :                 break;
    4655             : 
    4656             :             case DTK_ISOYEAR:
    4657         220 :                 result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4658         220 :                 break;
    4659             : 
    4660             :             case DTK_DOW:
    4661             :             case DTK_ISODOW:
    4662         220 :                 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    4663           0 :                     ereport(ERROR,
    4664             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4665             :                              errmsg("timestamp out of range")));
    4666         220 :                 result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
    4667         220 :                 if (val == DTK_ISODOW && result == 0)
    4668           0 :                     result = 7;
    4669         220 :                 break;
    4670             : 
    4671             :             case DTK_DOY:
    4672           0 :                 if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    4673           0 :                     ereport(ERROR,
    4674             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4675             :                              errmsg("timestamp out of range")));
    4676           0 :                 result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
    4677           0 :                           - date2j(tm->tm_year, 1, 1) + 1);
    4678           0 :                 break;
    4679             : 
    4680             :             case DTK_TZ:
    4681             :             case DTK_TZ_MINUTE:
    4682             :             case DTK_TZ_HOUR:
    4683             :             default:
    4684           0 :                 ereport(ERROR,
    4685             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4686             :                          errmsg("timestamp units \"%s\" not supported",
    4687             :                                 lowunits)));
    4688             :                 result = 0;
    4689             :         }
    4690             :     }
    4691           8 :     else if (type == RESERV)
    4692             :     {
    4693           8 :         switch (val)
    4694             :         {
    4695             :             case DTK_EPOCH:
    4696           8 :                 epoch = SetEpochTimestamp();
    4697             :                 /* try to avoid precision loss in subtraction */
    4698           8 :                 if (timestamp < (PG_INT64_MAX + epoch))
    4699           8 :                     result = (timestamp - epoch) / 1000000.0;
    4700             :                 else
    4701           0 :                     result = ((float8) timestamp - epoch) / 1000000.0;
    4702           8 :                 break;
    4703             : 
    4704             :             default:
    4705           0 :                 ereport(ERROR,
    4706             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4707             :                          errmsg("timestamp units \"%s\" not supported",
    4708             :                                 lowunits)));
    4709             :                 result = 0;
    4710             :         }
    4711             : 
    4712             :     }
    4713             :     else
    4714             :     {
    4715           0 :         ereport(ERROR,
    4716             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4717             :                  errmsg("timestamp units \"%s\" not recognized", lowunits)));
    4718             :         result = 0;
    4719             :     }
    4720             : 
    4721        2920 :     PG_RETURN_FLOAT8(result);
    4722             : }
    4723             : 
    4724             : /* timestamptz_part()
    4725             :  * Extract specified field from timestamp with time zone.
    4726             :  */
    4727             : Datum
    4728        2752 : timestamptz_part(PG_FUNCTION_ARGS)
    4729             : {
    4730        2752 :     text       *units = PG_GETARG_TEXT_PP(0);
    4731        2752 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    4732             :     float8      result;
    4733             :     Timestamp   epoch;
    4734             :     int         tz;
    4735             :     int         type,
    4736             :                 val;
    4737             :     char       *lowunits;
    4738             :     double      dummy;
    4739             :     fsec_t      fsec;
    4740             :     struct pg_tm tt,
    4741        2752 :                *tm = &tt;
    4742             : 
    4743        8256 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4744        8256 :                                             VARSIZE_ANY_EXHDR(units),
    4745             :                                             false);
    4746             : 
    4747        2752 :     type = DecodeUnits(0, lowunits, &val);
    4748        2752 :     if (type == UNKNOWN_FIELD)
    4749         500 :         type = DecodeSpecial(0, lowunits, &val);
    4750             : 
    4751        2752 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    4752             :     {
    4753          16 :         result = NonFiniteTimestampTzPart(type, val, lowunits,
    4754             :                                           TIMESTAMP_IS_NOBEGIN(timestamp),
    4755             :                                           true);
    4756          16 :         if (result)
    4757           8 :             PG_RETURN_FLOAT8(result);
    4758             :         else
    4759           8 :             PG_RETURN_NULL();
    4760             :     }
    4761             : 
    4762        2736 :     if (type == UNITS)
    4763             :     {
    4764        2692 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    4765           0 :             ereport(ERROR,
    4766             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4767             :                      errmsg("timestamp out of range")));
    4768             : 
    4769        2692 :         switch (val)
    4770             :         {
    4771             :             case DTK_TZ:
    4772           0 :                 result = -tz;
    4773           0 :                 break;
    4774             : 
    4775             :             case DTK_TZ_MINUTE:
    4776           0 :                 result = -tz;
    4777           0 :                 result /= MINS_PER_HOUR;
    4778           0 :                 FMODULO(result, dummy, (double) MINS_PER_HOUR);
    4779           0 :                 break;
    4780             : 
    4781             :             case DTK_TZ_HOUR:
    4782           0 :                 dummy = -tz;
    4783           0 :                 FMODULO(dummy, result, (double) SECS_PER_HOUR);
    4784           0 :                 break;
    4785             : 
    4786             :             case DTK_MICROSEC:
    4787         224 :                 result = tm->tm_sec * 1000000.0 + fsec;
    4788         224 :                 break;
    4789             : 
    4790             :             case DTK_MILLISEC:
    4791         224 :                 result = tm->tm_sec * 1000.0 + fsec / 1000.0;
    4792         224 :                 break;
    4793             : 
    4794             :             case DTK_SECOND:
    4795         224 :                 result = tm->tm_sec + fsec / 1000000.0;
    4796         224 :                 break;
    4797             : 
    4798             :             case DTK_MINUTE:
    4799         224 :                 result = tm->tm_min;
    4800         224 :                 break;
    4801             : 
    4802             :             case DTK_HOUR:
    4803         224 :                 result = tm->tm_hour;
    4804         224 :                 break;
    4805             : 
    4806             :             case DTK_DAY:
    4807         224 :                 result = tm->tm_mday;
    4808         224 :                 break;
    4809             : 
    4810             :             case DTK_MONTH:
    4811         224 :                 result = tm->tm_mon;
    4812         224 :                 break;
    4813             : 
    4814             :             case DTK_QUARTER:
    4815         224 :                 result = (tm->tm_mon - 1) / 3 + 1;
    4816         224 :                 break;
    4817             : 
    4818             :             case DTK_WEEK:
    4819         224 :                 result = (float8) date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4820         224 :                 break;
    4821             : 
    4822             :             case DTK_YEAR:
    4823         224 :                 if (tm->tm_year > 0)
    4824         224 :                     result = tm->tm_year;
    4825             :                 else
    4826             :                     /* there is no year 0, just 1 BC and 1 AD */
    4827           0 :                     result = tm->tm_year - 1;
    4828         224 :                 break;
    4829             : 
    4830             :             case DTK_DECADE:
    4831             :                 /* see comments in timestamp_part */
    4832           0 :                 if (tm->tm_year > 0)
    4833           0 :                     result = tm->tm_year / 10;
    4834             :                 else
    4835           0 :                     result = -((8 - (tm->tm_year - 1)) / 10);
    4836           0 :                 break;
    4837             : 
    4838             :             case DTK_CENTURY:
    4839             :                 /* see comments in timestamp_part */
    4840           4 :                 if (tm->tm_year > 0)
    4841           4 :                     result = (tm->tm_year + 99) / 100;
    4842             :                 else
    4843           0 :                     result = -((99 - (tm->tm_year - 1)) / 100);
    4844           4 :                 break;
    4845             : 
    4846             :             case DTK_MILLENNIUM:
    4847             :                 /* see comments in timestamp_part */
    4848           0 :                 if (tm->tm_year > 0)
    4849           0 :                     result = (tm->tm_year + 999) / 1000;
    4850             :                 else
    4851           0 :                     result = -((999 - (tm->tm_year - 1)) / 1000);
    4852           0 :                 break;
    4853             : 
    4854             :             case DTK_JULIAN:
    4855           0 :                 result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4856           0 :                 result += ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
    4857           0 :                            tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY;
    4858           0 :                 break;
    4859             : 
    4860             :             case DTK_ISOYEAR:
    4861         224 :                 result = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
    4862         224 :                 break;
    4863             : 
    4864             :             case DTK_DOW:
    4865             :             case DTK_ISODOW:
    4866         224 :                 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    4867           0 :                     ereport(ERROR,
    4868             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4869             :                              errmsg("timestamp out of range")));
    4870         224 :                 result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
    4871         224 :                 if (val == DTK_ISODOW && result == 0)
    4872           0 :                     result = 7;
    4873         224 :                 break;
    4874             : 
    4875             :             case DTK_DOY:
    4876           0 :                 if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    4877           0 :                     ereport(ERROR,
    4878             :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4879             :                              errmsg("timestamp out of range")));
    4880           0 :                 result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
    4881           0 :                           - date2j(tm->tm_year, 1, 1) + 1);
    4882           0 :                 break;
    4883             : 
    4884             :             default:
    4885           0 :                 ereport(ERROR,
    4886             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4887             :                          errmsg("timestamp with time zone units \"%s\" not supported",
    4888             :                                 lowunits)));
    4889             :                 result = 0;
    4890             :         }
    4891             : 
    4892             :     }
    4893          44 :     else if (type == RESERV)
    4894             :     {
    4895          44 :         switch (val)
    4896             :         {
    4897             :             case DTK_EPOCH:
    4898          44 :                 epoch = SetEpochTimestamp();
    4899             :                 /* try to avoid precision loss in subtraction */
    4900          44 :                 if (timestamp < (PG_INT64_MAX + epoch))
    4901          44 :                     result = (timestamp - epoch) / 1000000.0;
    4902             :                 else
    4903           0 :                     result = ((float8) timestamp - epoch) / 1000000.0;
    4904          44 :                 break;
    4905             : 
    4906             :             default:
    4907           0 :                 ereport(ERROR,
    4908             :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4909             :                          errmsg("timestamp with time zone units \"%s\" not supported",
    4910             :                                 lowunits)));
    4911             :                 result = 0;
    4912             :         }
    4913             :     }
    4914             :     else
    4915             :     {
    4916           0 :         ereport(ERROR,
    4917             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    4918             :                  errmsg("timestamp with time zone units \"%s\" not recognized",
    4919             :                         lowunits)));
    4920             : 
    4921             :         result = 0;
    4922             :     }
    4923             : 
    4924        2736 :     PG_RETURN_FLOAT8(result);
    4925             : }
    4926             : 
    4927             : 
    4928             : /* interval_part()
    4929             :  * Extract specified field from interval.
    4930             :  */
    4931             : Datum
    4932          20 : interval_part(PG_FUNCTION_ARGS)
    4933             : {
    4934          20 :     text       *units = PG_GETARG_TEXT_PP(0);
    4935          20 :     Interval   *interval = PG_GETARG_INTERVAL_P(1);
    4936             :     float8      result;
    4937             :     int         type,
    4938             :                 val;
    4939             :     char       *lowunits;
    4940             :     fsec_t      fsec;
    4941             :     struct pg_tm tt,
    4942          20 :                *tm = &tt;
    4943             : 
    4944          60 :     lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
    4945          60 :                                             VARSIZE_ANY_EXHDR(units),
    4946             :                                             false);
    4947             : 
    4948          20 :     type = DecodeUnits(0, lowunits, &val);
    4949          20 :     if (type == UNKNOWN_FIELD)
    4950           4 :         type = DecodeSpecial(0, lowunits, &val);
    4951             : 
    4952          20 :     if (type == UNITS)
    4953             :     {
    4954          16 :         if (interval2tm(*interval, tm, &fsec) == 0)
    4955             :         {
    4956          16 :             switch (val)
    4957             :             {
    4958             :                 case DTK_MICROSEC:
    4959           0 :                     result = tm->tm_sec * 1000000.0 + fsec;
    4960           0 :                     break;
    4961             : 
    4962             :                 case DTK_MILLISEC:
    4963           0 :                     result = tm->tm_sec * 1000.0 + fsec / 1000.0;
    4964           0 :                     break;
    4965             : 
    4966             :                 case DTK_SECOND:
    4967           0 :                     result = tm->tm_sec + fsec / 1000000.0;
    4968           0 :                     break;
    4969             : 
    4970             :                 case DTK_MINUTE:
    4971           0 :                     result = tm->tm_min;
    4972           0 :                     break;
    4973             : 
    4974             :                 case DTK_HOUR:
    4975           0 :                     result = tm->tm_hour;
    4976           0 :                     break;
    4977             : 
    4978             :                 case DTK_DAY:
    4979           0 :                     result = tm->tm_mday;
    4980           0 :                     break;
    4981             : 
    4982             :                 case DTK_MONTH:
    4983           0 :                     result = tm->tm_mon;
    4984           0 :                     break;
    4985             : 
    4986             :                 case DTK_QUARTER:
    4987           0 :                     result = (tm->tm_mon / 3) + 1;
    4988           0 :                     break;
    4989             : 
    4990             :                 case DTK_YEAR:
    4991           0 :                     result = tm->tm_year;
    4992           0 :                     break;
    4993             : 
    4994             :                 case DTK_DECADE:
    4995             :                     /* caution: C division may have negative remainder */
    4996           0 :                     result = tm->tm_year / 10;
    4997           0 :                     break;
    4998             : 
    4999             :                 case DTK_CENTURY:
    5000             :                     /* caution: C division may have negative remainder */
    5001          16 :                     result = tm->tm_year / 100;
    5002          16 :                     break;
    5003             : 
    5004             :                 case DTK_MILLENNIUM:
    5005             :                     /* caution: C division may have negative remainder */
    5006           0 :                     result = tm->tm_year / 1000;
    5007           0 :                     break;
    5008             : 
    5009             :                 default:
    5010           0 :                     ereport(ERROR,
    5011             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5012             :                              errmsg("interval units \"%s\" not supported",
    5013             :                                     lowunits)));
    5014             :                     result = 0;
    5015             :             }
    5016             : 
    5017             :         }
    5018             :         else
    5019             :         {
    5020           0 :             elog(ERROR, "could not convert interval to tm");
    5021             :             result = 0;
    5022             :         }
    5023             :     }
    5024           4 :     else if (type == RESERV && val == DTK_EPOCH)
    5025             :     {
    5026           4 :         result = interval->time / 1000000.0;
    5027           4 :         result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
    5028           4 :         result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
    5029           4 :         result += ((double) SECS_PER_DAY) * interval->day;
    5030             :     }
    5031             :     else
    5032             :     {
    5033           0 :         ereport(ERROR,
    5034             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5035             :                  errmsg("interval units \"%s\" not recognized",
    5036             :                         lowunits)));
    5037             :         result = 0;
    5038             :     }
    5039             : 
    5040          20 :     PG_RETURN_FLOAT8(result);
    5041             : }
    5042             : 
    5043             : 
    5044             : /*  timestamp_zone()
    5045             :  *  Encode timestamp type with specified time zone.
    5046             :  *  This function is just timestamp2timestamptz() except instead of
    5047             :  *  shifting to the global timezone, we shift to the specified timezone.
    5048             :  *  This is different from the other AT TIME ZONE cases because instead
    5049             :  *  of shifting _to_ a new time zone, it sets the time to _be_ the
    5050             :  *  specified timezone.
    5051             :  */
    5052             : Datum
    5053         112 : timestamp_zone(PG_FUNCTION_ARGS)
    5054             : {
    5055         112 :     text       *zone = PG_GETARG_TEXT_PP(0);
    5056         112 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    5057             :     TimestampTz result;
    5058             :     int         tz;
    5059             :     char        tzname[TZ_STRLEN_MAX + 1];
    5060             :     char       *lowzone;
    5061             :     int         type,
    5062             :                 val;
    5063             :     pg_tz      *tzp;
    5064             :     struct pg_tm tm;
    5065             :     fsec_t      fsec;
    5066             : 
    5067         112 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5068           0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    5069             : 
    5070             :     /*
    5071             :      * Look up the requested timezone.  First we look in the timezone
    5072             :      * abbreviation table (to handle cases like "EST"), and if that fails, we
    5073             :      * look in the timezone database (to handle cases like
    5074             :      * "America/New_York").  (This matches the order in which timestamp input
    5075             :      * checks the cases; it's important because the timezone database unwisely
    5076             :      * uses a few zone names that are identical to offset abbreviations.)
    5077             :      */
    5078         112 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    5079             : 
    5080             :     /* DecodeTimezoneAbbrev requires lowercase input */
    5081         112 :     lowzone = downcase_truncate_identifier(tzname,
    5082         112 :                                            strlen(tzname),
    5083             :                                            false);
    5084             : 
    5085         112 :     type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
    5086             : 
    5087         112 :     if (type == TZ || type == DTZ)
    5088             :     {
    5089             :         /* fixed-offset abbreviation */
    5090           0 :         tz = val;
    5091           0 :         result = dt2local(timestamp, tz);
    5092             :     }
    5093         112 :     else if (type == DYNTZ)
    5094             :     {
    5095             :         /* dynamic-offset abbreviation, resolve using specified time */
    5096          56 :         if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
    5097           0 :             ereport(ERROR,
    5098             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5099             :                      errmsg("timestamp out of range")));
    5100          56 :         tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
    5101          56 :         result = dt2local(timestamp, tz);
    5102             :     }
    5103             :     else
    5104             :     {
    5105             :         /* try it as a full zone name */
    5106          56 :         tzp = pg_tzset(tzname);
    5107          56 :         if (tzp)
    5108             :         {
    5109             :             /* Apply the timezone change */
    5110          56 :             if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
    5111           0 :                 ereport(ERROR,
    5112             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5113             :                          errmsg("timestamp out of range")));
    5114          56 :             tz = DetermineTimeZoneOffset(&tm, tzp);
    5115          56 :             if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
    5116           0 :                 ereport(ERROR,
    5117             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5118             :                          errmsg("timestamp out of range")));
    5119             :         }
    5120             :         else
    5121             :         {
    5122           0 :             ereport(ERROR,
    5123             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5124             :                      errmsg("time zone \"%s\" not recognized", tzname)));
    5125             :             result = 0;         /* keep compiler quiet */
    5126             :         }
    5127             :     }
    5128             : 
    5129         112 :     if (!IS_VALID_TIMESTAMP(result))
    5130           0 :         ereport(ERROR,
    5131             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5132             :                  errmsg("timestamp out of range")));
    5133             : 
    5134         112 :     PG_RETURN_TIMESTAMPTZ(result);
    5135             : }
    5136             : 
    5137             : /* timestamp_izone()
    5138             :  * Encode timestamp type with specified time interval as time zone.
    5139             :  */
    5140             : Datum
    5141           0 : timestamp_izone(PG_FUNCTION_ARGS)
    5142             : {
    5143           0 :     Interval   *zone = PG_GETARG_INTERVAL_P(0);
    5144           0 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(1);
    5145             :     TimestampTz result;
    5146             :     int         tz;
    5147             : 
    5148           0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5149           0 :         PG_RETURN_TIMESTAMPTZ(timestamp);
    5150             : 
    5151           0 :     if (zone->month != 0 || zone->day != 0)
    5152           0 :         ereport(ERROR,
    5153             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5154             :                  errmsg("interval time zone \"%s\" must not include months or days",
    5155             :                         DatumGetCString(DirectFunctionCall1(interval_out,
    5156             :                                                             PointerGetDatum(zone))))));
    5157             : 
    5158           0 :     tz = zone->time / USECS_PER_SEC;
    5159             : 
    5160           0 :     result = dt2local(timestamp, tz);
    5161             : 
    5162           0 :     if (!IS_VALID_TIMESTAMP(result))
    5163           0 :         ereport(ERROR,
    5164             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5165             :                  errmsg("timestamp out of range")));
    5166             : 
    5167           0 :     PG_RETURN_TIMESTAMPTZ(result);
    5168             : }                               /* timestamp_izone() */
    5169             : 
    5170             : /* TimestampTimestampTzRequiresRewrite()
    5171             :  *
    5172             :  * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
    5173             :  * timestamptz_timestamp to be no-ops, where the return value has the same
    5174             :  * bits as the argument.  Since project convention is to assume a GUC changes
    5175             :  * no more often than STABLE functions change, the answer is valid that long.
    5176             :  */
    5177             : bool
    5178          12 : TimestampTimestampTzRequiresRewrite(void)
    5179             : {
    5180             :     long        offset;
    5181             : 
    5182          12 :     if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
    5183           8 :         PG_RETURN_BOOL(false);
    5184           4 :     PG_RETURN_BOOL(true);
    5185             : }
    5186             : 
    5187             : /* timestamp_timestamptz()
    5188             :  * Convert local timestamp to timestamp at GMT
    5189             :  */
    5190             : Datum
    5191          72 : timestamp_timestamptz(PG_FUNCTION_ARGS)
    5192             : {
    5193          72 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
    5194             : 
    5195          72 :     PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
    5196             : }
    5197             : 
    5198             : static TimestampTz
    5199        5996 : timestamp2timestamptz(Timestamp timestamp)
    5200             : {
    5201             :     TimestampTz result;
    5202             :     struct pg_tm tt,
    5203        5996 :                *tm = &tt;
    5204             :     fsec_t      fsec;
    5205             :     int         tz;
    5206             : 
    5207        5996 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5208           0 :         result = timestamp;
    5209             :     else
    5210             :     {
    5211        5996 :         if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
    5212           0 :             ereport(ERROR,
    5213             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5214             :                      errmsg("timestamp out of range")));
    5215             : 
    5216        5996 :         tz = DetermineTimeZoneOffset(tm, session_timezone);
    5217             : 
    5218        5996 :         if (tm2timestamp(tm, fsec, &tz, &result) != 0)
    5219           0 :             ereport(ERROR,
    5220             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5221             :                      errmsg("timestamp out of range")));
    5222             :     }
    5223             : 
    5224        5996 :     return result;
    5225             : }
    5226             : 
    5227             : /* timestamptz_timestamp()
    5228             :  * Convert timestamp at GMT to local timestamp
    5229             :  */
    5230             : Datum
    5231         250 : timestamptz_timestamp(PG_FUNCTION_ARGS)
    5232             : {
    5233         250 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
    5234             : 
    5235         250 :     PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
    5236             : }
    5237             : 
    5238             : static Timestamp
    5239         286 : timestamptz2timestamp(TimestampTz timestamp)
    5240             : {
    5241             :     Timestamp   result;
    5242             :     struct pg_tm tt,
    5243         286 :                *tm = &tt;
    5244             :     fsec_t      fsec;
    5245             :     int         tz;
    5246             : 
    5247         286 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5248           0 :         result = timestamp;
    5249             :     else
    5250             :     {
    5251         286 :         if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
    5252           0 :             ereport(ERROR,
    5253             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5254             :                      errmsg("timestamp out of range")));
    5255         286 :         if (tm2timestamp(tm, fsec, NULL, &result) != 0)
    5256           0 :             ereport(ERROR,
    5257             :                     (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5258             :                      errmsg("timestamp out of range")));
    5259             :     }
    5260         286 :     return result;
    5261             : }
    5262             : 
    5263             : /* timestamptz_zone()
    5264             :  * Evaluate timestamp with time zone type at the specified time zone.
    5265             :  * Returns a timestamp without time zone.
    5266             :  */
    5267             : Datum
    5268         124 : timestamptz_zone(PG_FUNCTION_ARGS)
    5269             : {
    5270         124 :     text       *zone = PG_GETARG_TEXT_PP(0);
    5271         124 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    5272             :     Timestamp   result;
    5273             :     int         tz;
    5274             :     char        tzname[TZ_STRLEN_MAX + 1];
    5275             :     char       *lowzone;
    5276             :     int         type,
    5277             :                 val;
    5278             :     pg_tz      *tzp;
    5279             : 
    5280         124 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5281           0 :         PG_RETURN_TIMESTAMP(timestamp);
    5282             : 
    5283             :     /*
    5284             :      * Look up the requested timezone.  First we look in the timezone
    5285             :      * abbreviation table (to handle cases like "EST"), and if that fails, we
    5286             :      * look in the timezone database (to handle cases like
    5287             :      * "America/New_York").  (This matches the order in which timestamp input
    5288             :      * checks the cases; it's important because the timezone database unwisely
    5289             :      * uses a few zone names that are identical to offset abbreviations.)
    5290             :      */
    5291         124 :     text_to_cstring_buffer(zone, tzname, sizeof(tzname));
    5292             : 
    5293             :     /* DecodeTimezoneAbbrev requires lowercase input */
    5294         124 :     lowzone = downcase_truncate_identifier(tzname,
    5295         124 :                                            strlen(tzname),
    5296             :                                            false);
    5297             : 
    5298         124 :     type = DecodeTimezoneAbbrev(0, lowzone, &val, &tzp);
    5299             : 
    5300         124 :     if (type == TZ || type == DTZ)
    5301             :     {
    5302             :         /* fixed-offset abbreviation */
    5303          16 :         tz = -val;
    5304          16 :         result = dt2local(timestamp, tz);
    5305             :     }
    5306         108 :     else if (type == DYNTZ)
    5307             :     {
    5308             :         /* dynamic-offset abbreviation, resolve using specified time */
    5309             :         int         isdst;
    5310             : 
    5311          48 :         tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
    5312          48 :         result = dt2local(timestamp, tz);
    5313             :     }
    5314             :     else
    5315             :     {
    5316             :         /* try it as a full zone name */
    5317          60 :         tzp = pg_tzset(tzname);
    5318          60 :         if (tzp)
    5319             :         {
    5320             :             /* Apply the timezone change */
    5321             :             struct pg_tm tm;
    5322             :             fsec_t      fsec;
    5323             : 
    5324          56 :             if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
    5325           0 :                 ereport(ERROR,
    5326             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5327             :                          errmsg("timestamp out of range")));
    5328          56 :             if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
    5329           0 :                 ereport(ERROR,
    5330             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5331             :                          errmsg("timestamp out of range")));
    5332             :         }
    5333             :         else
    5334             :         {
    5335           4 :             ereport(ERROR,
    5336             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5337             :                      errmsg("time zone \"%s\" not recognized", tzname)));
    5338             :             result = 0;         /* keep compiler quiet */
    5339             :         }
    5340             :     }
    5341             : 
    5342         120 :     if (!IS_VALID_TIMESTAMP(result))
    5343           0 :         ereport(ERROR,
    5344             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5345             :                  errmsg("timestamp out of range")));
    5346             : 
    5347         120 :     PG_RETURN_TIMESTAMP(result);
    5348             : }
    5349             : 
    5350             : /* timestamptz_izone()
    5351             :  * Encode timestamp with time zone type with specified time interval as time zone.
    5352             :  * Returns a timestamp without time zone.
    5353             :  */
    5354             : Datum
    5355           0 : timestamptz_izone(PG_FUNCTION_ARGS)
    5356             : {
    5357           0 :     Interval   *zone = PG_GETARG_INTERVAL_P(0);
    5358           0 :     TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
    5359             :     Timestamp   result;
    5360             :     int         tz;
    5361             : 
    5362           0 :     if (TIMESTAMP_NOT_FINITE(timestamp))
    5363           0 :         PG_RETURN_TIMESTAMP(timestamp);
    5364             : 
    5365           0 :     if (zone->month != 0 || zone->day != 0)
    5366           0 :         ereport(ERROR,
    5367             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5368             :                  errmsg("interval time zone \"%s\" must not include months or days",
    5369             :                         DatumGetCString(DirectFunctionCall1(interval_out,
    5370             :                                                             PointerGetDatum(zone))))));
    5371             : 
    5372           0 :     tz = -(zone->time / USECS_PER_SEC);
    5373             : 
    5374           0 :     result = dt2local(timestamp, tz);
    5375             : 
    5376           0 :     if (!IS_VALID_TIMESTAMP(result))
    5377           0 :         ereport(ERROR,
    5378             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    5379             :                  errmsg("timestamp out of range")));
    5380             : 
    5381           0 :     PG_RETURN_TIMESTAMP(result);
    5382             : }
    5383             : 
    5384             : /* generate_series_timestamp()
    5385             :  * Generate the set of timestamps from start to finish by step
    5386             :  */
    5387             : Datum
    5388           0 : generate_series_timestamp(PG_FUNCTION_ARGS)
    5389             : {
    5390             :     FuncCallContext *funcctx;
    5391             :     generate_series_timestamp_fctx *fctx;
    5392             :     Timestamp   result;
    5393             : 
    5394             :     /* stuff done only on the first call of the function */
    5395           0 :     if (SRF_IS_FIRSTCALL())
    5396             :     {
    5397           0 :         Timestamp   start = PG_GETARG_TIMESTAMP(0);
    5398           0 :         Timestamp   finish = PG_GETARG_TIMESTAMP(1);
    5399           0 :         Interval   *step = PG_GETARG_INTERVAL_P(2);
    5400             :         MemoryContext oldcontext;
    5401             :         Interval    interval_zero;
    5402             : 
    5403             :         /* create a function context for cross-call persistence */
    5404           0 :         funcctx = SRF_FIRSTCALL_INIT();
    5405             : 
    5406             :         /*
    5407             :          * switch to memory context appropriate for multiple function calls
    5408             :          */
    5409           0 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    5410             : 
    5411             :         /* allocate memory for user context */
    5412           0 :         fctx = (generate_series_timestamp_fctx *)
    5413             :             palloc(sizeof(generate_series_timestamp_fctx));
    5414             : 
    5415             :         /*
    5416             :          * Use fctx to keep state from call to call. Seed current with the
    5417             :          * original start value
    5418             :          */
    5419           0 :         fctx->current = start;
    5420           0 :         fctx->finish = finish;
    5421           0 :         fctx->step = *step;
    5422             : 
    5423             :         /* Determine sign of the interval */
    5424           0 :         MemSet(&interval_zero, 0, sizeof(Interval));
    5425           0 :         fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
    5426             : 
    5427           0 :         if (fctx->step_sign == 0)
    5428           0 :             ereport(ERROR,
    5429             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5430             :                      errmsg("step size cannot equal zero")));
    5431             : 
    5432           0 :         funcctx->user_fctx = fctx;
    5433           0 :         MemoryContextSwitchTo(oldcontext);
    5434             :     }
    5435             : 
    5436             :     /* stuff done on every call of the function */
    5437           0 :     funcctx = SRF_PERCALL_SETUP();
    5438             : 
    5439             :     /*
    5440             :      * get the saved state and use current as the result for this iteration
    5441             :      */
    5442           0 :     fctx = funcctx->user_fctx;
    5443           0 :     result = fctx->current;
    5444             : 
    5445           0 :     if (fctx->step_sign > 0 ?
    5446           0 :         timestamp_cmp_internal(result, fctx->finish) <= 0 :
    5447           0 :         timestamp_cmp_internal(result, fctx->finish) >= 0)
    5448             :     {
    5449             :         /* increment current in preparation for next iteration */
    5450           0 :         fctx->current = DatumGetTimestamp(
    5451             :                                           DirectFunctionCall2(timestamp_pl_interval,
    5452             :                                                               TimestampGetDatum(fctx->current),
    5453             :                                                               PointerGetDatum(&fctx->step)));
    5454             : 
    5455             :         /* do when there is more left to send */
    5456           0 :         SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
    5457             :     }
    5458             :     else
    5459             :     {
    5460             :         /* do when there is no more left */
    5461           0 :         SRF_RETURN_DONE(funcctx);
    5462             :     }
    5463             : }
    5464             : 
    5465             : /* generate_series_timestamptz()
    5466             :  * Generate the set of timestamps from start to finish by step
    5467             :  */
    5468             : Datum
    5469           0 : generate_series_timestamptz(PG_FUNCTION_ARGS)
    5470             : {
    5471             :     FuncCallContext *funcctx;
    5472             :     generate_series_timestamptz_fctx *fctx;
    5473             :     TimestampTz result;
    5474             : 
    5475             :     /* stuff done only on the first call of the function */
    5476           0 :     if (SRF_IS_FIRSTCALL())
    5477             :     {
    5478           0 :         TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
    5479           0 :         TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
    5480           0 :         Interval   *step = PG_GETARG_INTERVAL_P(2);
    5481             :         MemoryContext oldcontext;
    5482             :         Interval    interval_zero;
    5483             : 
    5484             :         /* create a function context for cross-call persistence */
    5485           0 :         funcctx = SRF_FIRSTCALL_INIT();
    5486             : 
    5487             :         /*
    5488             :          * switch to memory context appropriate for multiple function calls
    5489             :          */
    5490           0 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    5491             : 
    5492             :         /* allocate memory for user context */
    5493           0 :         fctx = (generate_series_timestamptz_fctx *)
    5494             :             palloc(sizeof(generate_series_timestamptz_fctx));
    5495             : 
    5496             :         /*
    5497             :          * Use fctx to keep state from call to call. Seed current with the
    5498             :          * original start value
    5499             :          */
    5500           0 :         fctx->current = start;
    5501           0 :         fctx->finish = finish;
    5502           0 :         fctx->step = *step;
    5503             : 
    5504             :         /* Determine sign of the interval */
    5505           0 :         MemSet(&interval_zero, 0, sizeof(Interval));
    5506           0 :         fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
    5507             : 
    5508           0 :         if (fctx->step_sign == 0)
    5509           0 :             ereport(ERROR,
    5510             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    5511             :                      errmsg("step size cannot equal zero")));
    5512             : 
    5513           0 :         funcctx->user_fctx = fctx;
    5514           0 :         MemoryContextSwitchTo(oldcontext);
    5515             :     }
    5516             : 
    5517             :     /* stuff done on every call of the function */
    5518           0 :     funcctx = SRF_PERCALL_SETUP();
    5519             : 
    5520             :     /*
    5521             :      * get the saved state and use current as the result for this iteration
    5522             :      */
    5523           0 :     fctx = funcctx->user_fctx;
    5524           0 :     result = fctx->current;
    5525             : 
    5526           0 :     if (fctx->step_sign > 0 ?
    5527           0 :         timestamp_cmp_internal(result, fctx->finish) <= 0 :
    5528           0 :         timestamp_cmp_internal(result, fctx->finish) >= 0)
    5529             :     {
    5530             :         /* increment current in preparation for next iteration */
    5531           0 :         fctx->current = DatumGetTimestampTz(
    5532             :                                             DirectFunctionCall2(timestamptz_pl_interval,
    5533             :                                                                 TimestampTzGetDatum(fctx->current),
    5534             :                                                                 PointerGetDatum(&fctx->step)));
    5535             : 
    5536             :         /* do when there is more left to send */
    5537           0 :         SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
    5538             :     }
    5539             :     else
    5540             :     {
    5541             :         /* do when there is no more left */
    5542           0 :         SRF_RETURN_DONE(funcctx);
    5543             :     }
    5544             : }

Generated by: LCOV version 1.13