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

Generated by: LCOV version 1.13