Coverage Report

Created: 2025-08-12 06:43

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