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

Generated by: LCOV version 1.11