Coverage Report

Created: 2026-08-13 07:12

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