LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - timestamp.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 73.4 % 2230 1636 15 112 293 178 93 884 114 545 305 902 18 73
Current Date: 2023-04-08 15:15:32 Functions: 84.2 % 171 144 1 25 1 118 18 8 25 125 9
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a