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

Generated by: LCOV version 1.13