Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/adt/date.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * date.c
4
 *    implements DATE and TIME data types specified in SQL standard
5
 *
6
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994-5, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/utils/adt/date.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
16
#include "postgres.h"
17
18
#include <ctype.h>
19
#include <limits.h>
20
#include <float.h>
21
#include <math.h>
22
#include <time.h>
23
24
#include "access/xact.h"
25
#include "catalog/pg_type.h"
26
#include "common/hashfn.h"
27
#include "common/int.h"
28
#include "libpq/pqformat.h"
29
#include "miscadmin.h"
30
#include "nodes/supportnodes.h"
31
#include "parser/scansup.h"
32
#include "utils/array.h"
33
#include "utils/builtins.h"
34
#include "utils/date.h"
35
#include "utils/datetime.h"
36
#include "utils/numeric.h"
37
#include "utils/skipsupport.h"
38
#include "utils/sortsupport.h"
39
40
/*
41
 * gcc's -ffast-math switch breaks routines that expect exact results from
42
 * expressions like timeval / SECS_PER_HOUR, where timeval is double.
43
 */
44
#ifdef __FAST_MATH__
45
#error -ffast-math is known to break this code
46
#endif
47
48
49
/* common code for timetypmodin and timetztypmodin */
50
static int32
51
anytime_typmodin(bool istz, ArrayType *ta)
52
0
{
53
0
  int32    *tl;
54
0
  int     n;
55
56
0
  tl = ArrayGetIntegerTypmods(ta, &n);
57
58
  /*
59
   * we're not too tense about good error message here because grammar
60
   * shouldn't allow wrong number of modifiers for TIME
61
   */
62
0
  if (n != 1)
63
0
    ereport(ERROR,
64
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
65
0
         errmsg("invalid type modifier")));
66
67
0
  return anytime_typmod_check(istz, tl[0]);
68
0
}
69
70
/* exported so parse_expr.c can use it */
71
int32
72
anytime_typmod_check(bool istz, int32 typmod)
73
{
74
  if (typmod < 0)
75
    ereport(ERROR,
76
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
77
         errmsg("TIME(%d)%s precision must not be negative",
78
            typmod, (istz ? " WITH TIME ZONE" : ""))));
79
  if (typmod > MAX_TIME_PRECISION)
80
  {
81
    ereport(WARNING,
82
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
83
         errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
84
            typmod, (istz ? " WITH TIME ZONE" : ""),
85
            MAX_TIME_PRECISION)));
86
    typmod = MAX_TIME_PRECISION;
87
  }
88
89
  return typmod;
90
}
91
92
/* common code for timetypmodout and timetztypmodout */
93
static char *
94
anytime_typmodout(bool istz, int32 typmod)
95
0
{
96
0
  const char *tz = istz ? " with time zone" : " without time zone";
97
98
0
  if (typmod >= 0)
99
0
    return psprintf("(%d)%s", (int) typmod, tz);
100
0
  else
101
0
    return pstrdup(tz);
102
0
}
103
104
105
/*****************************************************************************
106
 *   Date ADT
107
 *****************************************************************************/
108
109
110
/* date_in()
111
 * Given date text string, convert to internal date format.
112
 */
113
Datum
114
date_in(PG_FUNCTION_ARGS)
115
0
{
116
0
  char     *str = PG_GETARG_CSTRING(0);
117
0
  Node     *escontext = fcinfo->context;
118
0
  DateADT   date;
119
0
  fsec_t    fsec;
120
0
  struct pg_tm tt,
121
0
         *tm = &tt;
122
0
  int     tzp;
123
0
  int     dtype;
124
0
  int     nf;
125
0
  int     dterr;
126
0
  char     *field[MAXDATEFIELDS];
127
0
  int     ftype[MAXDATEFIELDS];
128
0
  char    workbuf[MAXDATELEN + 1];
129
0
  DateTimeErrorExtra extra;
130
131
0
  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
132
0
              field, ftype, MAXDATEFIELDS, &nf);
133
0
  if (dterr == 0)
134
0
    dterr = DecodeDateTime(field, ftype, nf,
135
0
                 &dtype, tm, &fsec, &tzp, &extra);
136
0
  if (dterr != 0)
137
0
  {
138
0
    DateTimeParseError(dterr, &extra, str, "date", escontext);
139
0
    PG_RETURN_NULL();
140
0
  }
141
142
0
  switch (dtype)
143
0
  {
144
0
    case DTK_DATE:
145
0
      break;
146
147
0
    case DTK_EPOCH:
148
0
      GetEpochTime(tm);
149
0
      break;
150
151
0
    case DTK_LATE:
152
0
      DATE_NOEND(date);
153
0
      PG_RETURN_DATEADT(date);
154
155
0
    case DTK_EARLY:
156
0
      DATE_NOBEGIN(date);
157
0
      PG_RETURN_DATEADT(date);
158
159
0
    default:
160
0
      DateTimeParseError(DTERR_BAD_FORMAT, &extra, str, "date", escontext);
161
0
      PG_RETURN_NULL();
162
0
  }
163
164
  /* Prevent overflow in Julian-day routines */
165
0
  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
166
0
    ereturn(escontext, (Datum) 0,
167
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
168
0
         errmsg("date out of range: \"%s\"", str)));
169
170
0
  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
171
172
  /* Now check for just-out-of-range dates */
173
0
  if (!IS_VALID_DATE(date))
174
0
    ereturn(escontext, (Datum) 0,
175
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
176
0
         errmsg("date out of range: \"%s\"", str)));
177
178
0
  PG_RETURN_DATEADT(date);
179
0
}
180
181
/* date_out()
182
 * Given internal format date, convert to text string.
183
 */
184
Datum
185
date_out(PG_FUNCTION_ARGS)
186
0
{
187
0
  DateADT   date = PG_GETARG_DATEADT(0);
188
0
  char     *result;
189
0
  struct pg_tm tt,
190
0
         *tm = &tt;
191
0
  char    buf[MAXDATELEN + 1];
192
193
0
  if (DATE_NOT_FINITE(date))
194
0
    EncodeSpecialDate(date, buf);
195
0
  else
196
0
  {
197
0
    j2date(date + POSTGRES_EPOCH_JDATE,
198
0
         &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
199
0
    EncodeDateOnly(tm, DateStyle, buf);
200
0
  }
201
202
0
  result = pstrdup(buf);
203
0
  PG_RETURN_CSTRING(result);
204
0
}
205
206
/*
207
 *    date_recv     - converts external binary format to date
208
 */
209
Datum
210
date_recv(PG_FUNCTION_ARGS)
211
0
{
212
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
213
0
  DateADT   result;
214
215
0
  result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
216
217
  /* Limit to the same range that date_in() accepts. */
218
0
  if (DATE_NOT_FINITE(result))
219
0
     /* ok */ ;
220
0
  else if (!IS_VALID_DATE(result))
221
0
    ereport(ERROR,
222
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
223
0
         errmsg("date out of range")));
224
225
0
  PG_RETURN_DATEADT(result);
226
0
}
227
228
/*
229
 *    date_send     - converts date to binary format
230
 */
231
Datum
232
date_send(PG_FUNCTION_ARGS)
233
0
{
234
0
  DateADT   date = PG_GETARG_DATEADT(0);
235
0
  StringInfoData buf;
236
237
0
  pq_begintypsend(&buf);
238
0
  pq_sendint32(&buf, date);
239
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
240
0
}
241
242
/*
243
 *    make_date     - date constructor
244
 */
245
Datum
246
make_date(PG_FUNCTION_ARGS)
247
0
{
248
0
  struct pg_tm tm;
249
0
  DateADT   date;
250
0
  int     dterr;
251
0
  bool    bc = false;
252
253
0
  tm.tm_year = PG_GETARG_INT32(0);
254
0
  tm.tm_mon = PG_GETARG_INT32(1);
255
0
  tm.tm_mday = PG_GETARG_INT32(2);
256
257
  /* Handle negative years as BC */
258
0
  if (tm.tm_year < 0)
259
0
  {
260
0
    int     year = tm.tm_year;
261
262
0
    bc = true;
263
0
    if (pg_neg_s32_overflow(year, &year))
264
0
      ereport(ERROR,
265
0
          (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
266
0
           errmsg("date field value out of range: %d-%02d-%02d",
267
0
              tm.tm_year, tm.tm_mon, tm.tm_mday)));
268
0
    tm.tm_year = year;
269
0
  }
270
271
0
  dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
272
273
0
  if (dterr != 0)
274
0
    ereport(ERROR,
275
0
        (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
276
0
         errmsg("date field value out of range: %d-%02d-%02d",
277
0
            tm.tm_year, tm.tm_mon, tm.tm_mday)));
278
279
  /* Prevent overflow in Julian-day routines */
280
0
  if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
281
0
    ereport(ERROR,
282
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
283
0
         errmsg("date out of range: %d-%02d-%02d",
284
0
            tm.tm_year, tm.tm_mon, tm.tm_mday)));
285
286
0
  date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
287
288
  /* Now check for just-out-of-range dates */
289
0
  if (!IS_VALID_DATE(date))
290
0
    ereport(ERROR,
291
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
292
0
         errmsg("date out of range: %d-%02d-%02d",
293
0
            tm.tm_year, tm.tm_mon, tm.tm_mday)));
294
295
0
  PG_RETURN_DATEADT(date);
296
0
}
297
298
/*
299
 * Convert reserved date values to string.
300
 */
301
void
302
EncodeSpecialDate(DateADT dt, char *str)
303
0
{
304
0
  if (DATE_IS_NOBEGIN(dt))
305
0
    strcpy(str, EARLY);
306
0
  else if (DATE_IS_NOEND(dt))
307
0
    strcpy(str, LATE);
308
0
  else            /* shouldn't happen */
309
0
    elog(ERROR, "invalid argument for EncodeSpecialDate");
310
0
}
311
312
313
/*
314
 * GetSQLCurrentDate -- implements CURRENT_DATE
315
 */
316
DateADT
317
GetSQLCurrentDate(void)
318
0
{
319
0
  struct pg_tm tm;
320
321
0
  static int  cache_year = 0;
322
0
  static int  cache_mon = 0;
323
0
  static int  cache_mday = 0;
324
0
  static DateADT cache_date;
325
326
0
  GetCurrentDateTime(&tm);
327
328
  /*
329
   * date2j involves several integer divisions; moreover, unless our session
330
   * lives across local midnight, we don't really have to do it more than
331
   * once.  So it seems worth having a separate cache here.
332
   */
333
0
  if (tm.tm_year != cache_year ||
334
0
    tm.tm_mon != cache_mon ||
335
0
    tm.tm_mday != cache_mday)
336
0
  {
337
0
    cache_date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
338
0
    cache_year = tm.tm_year;
339
0
    cache_mon = tm.tm_mon;
340
0
    cache_mday = tm.tm_mday;
341
0
  }
342
343
0
  return cache_date;
344
0
}
345
346
/*
347
 * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
348
 */
349
TimeTzADT *
350
GetSQLCurrentTime(int32 typmod)
351
0
{
352
0
  TimeTzADT  *result;
353
0
  struct pg_tm tt,
354
0
         *tm = &tt;
355
0
  fsec_t    fsec;
356
0
  int     tz;
357
358
0
  GetCurrentTimeUsec(tm, &fsec, &tz);
359
360
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
361
0
  tm2timetz(tm, fsec, tz, result);
362
0
  AdjustTimeForTypmod(&(result->time), typmod);
363
0
  return result;
364
0
}
365
366
/*
367
 * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
368
 */
369
TimeADT
370
GetSQLLocalTime(int32 typmod)
371
0
{
372
0
  TimeADT   result;
373
0
  struct pg_tm tt,
374
0
         *tm = &tt;
375
0
  fsec_t    fsec;
376
0
  int     tz;
377
378
0
  GetCurrentTimeUsec(tm, &fsec, &tz);
379
380
0
  tm2time(tm, fsec, &result);
381
0
  AdjustTimeForTypmod(&result, typmod);
382
0
  return result;
383
0
}
384
385
386
/*
387
 * Comparison functions for dates
388
 */
389
390
Datum
391
date_eq(PG_FUNCTION_ARGS)
392
0
{
393
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
394
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
395
396
0
  PG_RETURN_BOOL(dateVal1 == dateVal2);
397
0
}
398
399
Datum
400
date_ne(PG_FUNCTION_ARGS)
401
0
{
402
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
403
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
404
405
0
  PG_RETURN_BOOL(dateVal1 != dateVal2);
406
0
}
407
408
Datum
409
date_lt(PG_FUNCTION_ARGS)
410
0
{
411
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
412
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
413
414
0
  PG_RETURN_BOOL(dateVal1 < dateVal2);
415
0
}
416
417
Datum
418
date_le(PG_FUNCTION_ARGS)
419
0
{
420
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
421
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
422
423
0
  PG_RETURN_BOOL(dateVal1 <= dateVal2);
424
0
}
425
426
Datum
427
date_gt(PG_FUNCTION_ARGS)
428
0
{
429
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
430
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
431
432
0
  PG_RETURN_BOOL(dateVal1 > dateVal2);
433
0
}
434
435
Datum
436
date_ge(PG_FUNCTION_ARGS)
437
0
{
438
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
439
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
440
441
0
  PG_RETURN_BOOL(dateVal1 >= dateVal2);
442
0
}
443
444
Datum
445
date_cmp(PG_FUNCTION_ARGS)
446
0
{
447
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
448
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
449
450
0
  if (dateVal1 < dateVal2)
451
0
    PG_RETURN_INT32(-1);
452
0
  else if (dateVal1 > dateVal2)
453
0
    PG_RETURN_INT32(1);
454
0
  PG_RETURN_INT32(0);
455
0
}
456
457
Datum
458
date_sortsupport(PG_FUNCTION_ARGS)
459
0
{
460
0
  SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
461
462
0
  ssup->comparator = ssup_datum_int32_cmp;
463
0
  PG_RETURN_VOID();
464
0
}
465
466
static Datum
467
date_decrement(Relation rel, Datum existing, bool *underflow)
468
0
{
469
0
  DateADT   dexisting = DatumGetDateADT(existing);
470
471
0
  if (dexisting == DATEVAL_NOBEGIN)
472
0
  {
473
    /* return value is undefined */
474
0
    *underflow = true;
475
0
    return (Datum) 0;
476
0
  }
477
478
0
  *underflow = false;
479
0
  return DateADTGetDatum(dexisting - 1);
480
0
}
481
482
static Datum
483
date_increment(Relation rel, Datum existing, bool *overflow)
484
0
{
485
0
  DateADT   dexisting = DatumGetDateADT(existing);
486
487
0
  if (dexisting == DATEVAL_NOEND)
488
0
  {
489
    /* return value is undefined */
490
0
    *overflow = true;
491
0
    return (Datum) 0;
492
0
  }
493
494
0
  *overflow = false;
495
0
  return DateADTGetDatum(dexisting + 1);
496
0
}
497
498
Datum
499
date_skipsupport(PG_FUNCTION_ARGS)
500
0
{
501
0
  SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
502
503
0
  sksup->decrement = date_decrement;
504
0
  sksup->increment = date_increment;
505
0
  sksup->low_elem = DateADTGetDatum(DATEVAL_NOBEGIN);
506
0
  sksup->high_elem = DateADTGetDatum(DATEVAL_NOEND);
507
508
0
  PG_RETURN_VOID();
509
0
}
510
511
Datum
512
hashdate(PG_FUNCTION_ARGS)
513
0
{
514
0
  return hash_uint32(PG_GETARG_DATEADT(0));
515
0
}
516
517
Datum
518
hashdateextended(PG_FUNCTION_ARGS)
519
0
{
520
0
  return hash_uint32_extended(PG_GETARG_DATEADT(0), PG_GETARG_INT64(1));
521
0
}
522
523
Datum
524
date_finite(PG_FUNCTION_ARGS)
525
0
{
526
0
  DateADT   date = PG_GETARG_DATEADT(0);
527
528
0
  PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
529
0
}
530
531
Datum
532
date_larger(PG_FUNCTION_ARGS)
533
0
{
534
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
535
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
536
537
0
  PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
538
0
}
539
540
Datum
541
date_smaller(PG_FUNCTION_ARGS)
542
0
{
543
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
544
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
545
546
0
  PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
547
0
}
548
549
/* Compute difference between two dates in days.
550
 */
551
Datum
552
date_mi(PG_FUNCTION_ARGS)
553
0
{
554
0
  DateADT   dateVal1 = PG_GETARG_DATEADT(0);
555
0
  DateADT   dateVal2 = PG_GETARG_DATEADT(1);
556
557
0
  if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
558
0
    ereport(ERROR,
559
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
560
0
         errmsg("cannot subtract infinite dates")));
561
562
0
  PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
563
0
}
564
565
/* Add a number of days to a date, giving a new date.
566
 * Must handle both positive and negative numbers of days.
567
 */
568
Datum
569
date_pli(PG_FUNCTION_ARGS)
570
0
{
571
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
572
0
  int32   days = PG_GETARG_INT32(1);
573
0
  DateADT   result;
574
575
0
  if (DATE_NOT_FINITE(dateVal))
576
0
    PG_RETURN_DATEADT(dateVal); /* can't change infinity */
577
578
0
  result = dateVal + days;
579
580
  /* Check for integer overflow and out-of-allowed-range */
581
0
  if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
582
0
    !IS_VALID_DATE(result))
583
0
    ereport(ERROR,
584
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
585
0
         errmsg("date out of range")));
586
587
0
  PG_RETURN_DATEADT(result);
588
0
}
589
590
/* Subtract a number of days from a date, giving a new date.
591
 */
592
Datum
593
date_mii(PG_FUNCTION_ARGS)
594
0
{
595
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
596
0
  int32   days = PG_GETARG_INT32(1);
597
0
  DateADT   result;
598
599
0
  if (DATE_NOT_FINITE(dateVal))
600
0
    PG_RETURN_DATEADT(dateVal); /* can't change infinity */
601
602
0
  result = dateVal - days;
603
604
  /* Check for integer overflow and out-of-allowed-range */
605
0
  if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
606
0
    !IS_VALID_DATE(result))
607
0
    ereport(ERROR,
608
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
609
0
         errmsg("date out of range")));
610
611
0
  PG_RETURN_DATEADT(result);
612
0
}
613
614
615
/*
616
 * Promote date to timestamp.
617
 *
618
 * On successful conversion, *overflow is set to zero if it's not NULL.
619
 *
620
 * If the date is finite but out of the valid range for timestamp, then:
621
 * if overflow is NULL, we throw an out-of-range error.
622
 * if overflow is not NULL, we store +1 or -1 there to indicate the sign
623
 * of the overflow, and return the appropriate timestamp infinity.
624
 *
625
 * Note: *overflow = -1 is actually not possible currently, since both
626
 * datatypes have the same lower bound, Julian day zero.
627
 */
628
Timestamp
629
date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
630
0
{
631
0
  Timestamp result;
632
633
0
  if (overflow)
634
0
    *overflow = 0;
635
636
0
  if (DATE_IS_NOBEGIN(dateVal))
637
0
    TIMESTAMP_NOBEGIN(result);
638
0
  else if (DATE_IS_NOEND(dateVal))
639
0
    TIMESTAMP_NOEND(result);
640
0
  else
641
0
  {
642
    /*
643
     * Since dates have the same minimum values as timestamps, only upper
644
     * boundary need be checked for overflow.
645
     */
646
0
    if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
647
0
    {
648
0
      if (overflow)
649
0
      {
650
0
        *overflow = 1;
651
0
        TIMESTAMP_NOEND(result);
652
0
        return result;
653
0
      }
654
0
      else
655
0
      {
656
0
        ereport(ERROR,
657
0
            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
658
0
             errmsg("date out of range for timestamp")));
659
0
      }
660
0
    }
661
662
    /* date is days since 2000, timestamp is microseconds since same... */
663
0
    result = dateVal * USECS_PER_DAY;
664
0
  }
665
666
0
  return result;
667
0
}
668
669
/*
670
 * Promote date to timestamp, throwing error for overflow.
671
 */
672
static TimestampTz
673
date2timestamp(DateADT dateVal)
674
0
{
675
0
  return date2timestamp_opt_overflow(dateVal, NULL);
676
0
}
677
678
/*
679
 * Promote date to timestamp with time zone.
680
 *
681
 * On successful conversion, *overflow is set to zero if it's not NULL.
682
 *
683
 * If the date is finite but out of the valid range for timestamptz, then:
684
 * if overflow is NULL, we throw an out-of-range error.
685
 * if overflow is not NULL, we store +1 or -1 there to indicate the sign
686
 * of the overflow, and return the appropriate timestamptz infinity.
687
 */
688
TimestampTz
689
date2timestamptz_opt_overflow(DateADT dateVal, int *overflow)
690
0
{
691
0
  TimestampTz result;
692
0
  struct pg_tm tt,
693
0
         *tm = &tt;
694
0
  int     tz;
695
696
0
  if (overflow)
697
0
    *overflow = 0;
698
699
0
  if (DATE_IS_NOBEGIN(dateVal))
700
0
    TIMESTAMP_NOBEGIN(result);
701
0
  else if (DATE_IS_NOEND(dateVal))
702
0
    TIMESTAMP_NOEND(result);
703
0
  else
704
0
  {
705
    /*
706
     * Since dates have the same minimum values as timestamps, only upper
707
     * boundary need be checked for overflow.
708
     */
709
0
    if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
710
0
    {
711
0
      if (overflow)
712
0
      {
713
0
        *overflow = 1;
714
0
        TIMESTAMP_NOEND(result);
715
0
        return result;
716
0
      }
717
0
      else
718
0
      {
719
0
        ereport(ERROR,
720
0
            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
721
0
             errmsg("date out of range for timestamp")));
722
0
      }
723
0
    }
724
725
0
    j2date(dateVal + POSTGRES_EPOCH_JDATE,
726
0
         &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
727
0
    tm->tm_hour = 0;
728
0
    tm->tm_min = 0;
729
0
    tm->tm_sec = 0;
730
0
    tz = DetermineTimeZoneOffset(tm, session_timezone);
731
732
0
    result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
733
734
    /*
735
     * Since it is possible to go beyond allowed timestamptz range because
736
     * of time zone, check for allowed timestamp range after adding tz.
737
     */
738
0
    if (!IS_VALID_TIMESTAMP(result))
739
0
    {
740
0
      if (overflow)
741
0
      {
742
0
        if (result < MIN_TIMESTAMP)
743
0
        {
744
0
          *overflow = -1;
745
0
          TIMESTAMP_NOBEGIN(result);
746
0
        }
747
0
        else
748
0
        {
749
0
          *overflow = 1;
750
0
          TIMESTAMP_NOEND(result);
751
0
        }
752
0
      }
753
0
      else
754
0
      {
755
0
        ereport(ERROR,
756
0
            (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
757
0
             errmsg("date out of range for timestamp")));
758
0
      }
759
0
    }
760
0
  }
761
762
0
  return result;
763
0
}
764
765
/*
766
 * Promote date to timestamptz, throwing error for overflow.
767
 */
768
static TimestampTz
769
date2timestamptz(DateADT dateVal)
770
0
{
771
0
  return date2timestamptz_opt_overflow(dateVal, NULL);
772
0
}
773
774
/*
775
 * date2timestamp_no_overflow
776
 *
777
 * This is chartered to produce a double value that is numerically
778
 * equivalent to the corresponding Timestamp value, if the date is in the
779
 * valid range of Timestamps, but in any case not throw an overflow error.
780
 * We can do this since the numerical range of double is greater than
781
 * that of non-erroneous timestamps.  The results are currently only
782
 * used for statistical estimation purposes.
783
 */
784
double
785
date2timestamp_no_overflow(DateADT dateVal)
786
0
{
787
0
  double    result;
788
789
0
  if (DATE_IS_NOBEGIN(dateVal))
790
0
    result = -DBL_MAX;
791
0
  else if (DATE_IS_NOEND(dateVal))
792
0
    result = DBL_MAX;
793
0
  else
794
0
  {
795
    /* date is days since 2000, timestamp is microseconds since same... */
796
0
    result = dateVal * (double) USECS_PER_DAY;
797
0
  }
798
799
0
  return result;
800
0
}
801
802
803
/*
804
 * Crosstype comparison functions for dates
805
 */
806
807
int32
808
date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
809
0
{
810
0
  Timestamp dt1;
811
0
  int     overflow;
812
813
0
  dt1 = date2timestamp_opt_overflow(dateVal, &overflow);
814
0
  if (overflow > 0)
815
0
  {
816
    /* dt1 is larger than any finite timestamp, but less than infinity */
817
0
    return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
818
0
  }
819
0
  Assert(overflow == 0);    /* -1 case cannot occur */
820
821
0
  return timestamp_cmp_internal(dt1, dt2);
822
0
}
823
824
Datum
825
date_eq_timestamp(PG_FUNCTION_ARGS)
826
0
{
827
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
828
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
829
830
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) == 0);
831
0
}
832
833
Datum
834
date_ne_timestamp(PG_FUNCTION_ARGS)
835
0
{
836
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
837
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
838
839
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) != 0);
840
0
}
841
842
Datum
843
date_lt_timestamp(PG_FUNCTION_ARGS)
844
0
{
845
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
846
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
847
848
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) < 0);
849
0
}
850
851
Datum
852
date_gt_timestamp(PG_FUNCTION_ARGS)
853
0
{
854
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
855
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
856
857
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) > 0);
858
0
}
859
860
Datum
861
date_le_timestamp(PG_FUNCTION_ARGS)
862
0
{
863
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
864
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
865
866
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) <= 0);
867
0
}
868
869
Datum
870
date_ge_timestamp(PG_FUNCTION_ARGS)
871
0
{
872
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
873
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
874
875
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) >= 0);
876
0
}
877
878
Datum
879
date_cmp_timestamp(PG_FUNCTION_ARGS)
880
0
{
881
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
882
0
  Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
883
884
0
  PG_RETURN_INT32(date_cmp_timestamp_internal(dateVal, dt2));
885
0
}
886
887
int32
888
date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
889
0
{
890
0
  TimestampTz dt1;
891
0
  int     overflow;
892
893
0
  dt1 = date2timestamptz_opt_overflow(dateVal, &overflow);
894
0
  if (overflow > 0)
895
0
  {
896
    /* dt1 is larger than any finite timestamp, but less than infinity */
897
0
    return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
898
0
  }
899
0
  if (overflow < 0)
900
0
  {
901
    /* dt1 is less than any finite timestamp, but more than -infinity */
902
0
    return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
903
0
  }
904
905
0
  return timestamptz_cmp_internal(dt1, dt2);
906
0
}
907
908
Datum
909
date_eq_timestamptz(PG_FUNCTION_ARGS)
910
0
{
911
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
912
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
913
914
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) == 0);
915
0
}
916
917
Datum
918
date_ne_timestamptz(PG_FUNCTION_ARGS)
919
0
{
920
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
921
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
922
923
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) != 0);
924
0
}
925
926
Datum
927
date_lt_timestamptz(PG_FUNCTION_ARGS)
928
0
{
929
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
930
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
931
932
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) < 0);
933
0
}
934
935
Datum
936
date_gt_timestamptz(PG_FUNCTION_ARGS)
937
0
{
938
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
939
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
940
941
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) > 0);
942
0
}
943
944
Datum
945
date_le_timestamptz(PG_FUNCTION_ARGS)
946
0
{
947
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
948
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
949
950
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) <= 0);
951
0
}
952
953
Datum
954
date_ge_timestamptz(PG_FUNCTION_ARGS)
955
0
{
956
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
957
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
958
959
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) >= 0);
960
0
}
961
962
Datum
963
date_cmp_timestamptz(PG_FUNCTION_ARGS)
964
0
{
965
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
966
0
  TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
967
968
0
  PG_RETURN_INT32(date_cmp_timestamptz_internal(dateVal, dt2));
969
0
}
970
971
Datum
972
timestamp_eq_date(PG_FUNCTION_ARGS)
973
0
{
974
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
975
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
976
977
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) == 0);
978
0
}
979
980
Datum
981
timestamp_ne_date(PG_FUNCTION_ARGS)
982
0
{
983
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
984
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
985
986
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) != 0);
987
0
}
988
989
Datum
990
timestamp_lt_date(PG_FUNCTION_ARGS)
991
0
{
992
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
993
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
994
995
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) > 0);
996
0
}
997
998
Datum
999
timestamp_gt_date(PG_FUNCTION_ARGS)
1000
0
{
1001
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
1002
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1003
1004
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) < 0);
1005
0
}
1006
1007
Datum
1008
timestamp_le_date(PG_FUNCTION_ARGS)
1009
0
{
1010
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
1011
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1012
1013
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) >= 0);
1014
0
}
1015
1016
Datum
1017
timestamp_ge_date(PG_FUNCTION_ARGS)
1018
0
{
1019
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
1020
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1021
1022
0
  PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) <= 0);
1023
0
}
1024
1025
Datum
1026
timestamp_cmp_date(PG_FUNCTION_ARGS)
1027
0
{
1028
0
  Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
1029
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1030
1031
0
  PG_RETURN_INT32(-date_cmp_timestamp_internal(dateVal, dt1));
1032
0
}
1033
1034
Datum
1035
timestamptz_eq_date(PG_FUNCTION_ARGS)
1036
0
{
1037
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1038
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1039
1040
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) == 0);
1041
0
}
1042
1043
Datum
1044
timestamptz_ne_date(PG_FUNCTION_ARGS)
1045
0
{
1046
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1047
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1048
1049
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) != 0);
1050
0
}
1051
1052
Datum
1053
timestamptz_lt_date(PG_FUNCTION_ARGS)
1054
0
{
1055
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1056
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1057
1058
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) > 0);
1059
0
}
1060
1061
Datum
1062
timestamptz_gt_date(PG_FUNCTION_ARGS)
1063
0
{
1064
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1065
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1066
1067
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) < 0);
1068
0
}
1069
1070
Datum
1071
timestamptz_le_date(PG_FUNCTION_ARGS)
1072
0
{
1073
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1074
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1075
1076
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) >= 0);
1077
0
}
1078
1079
Datum
1080
timestamptz_ge_date(PG_FUNCTION_ARGS)
1081
0
{
1082
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1083
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1084
1085
0
  PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) <= 0);
1086
0
}
1087
1088
Datum
1089
timestamptz_cmp_date(PG_FUNCTION_ARGS)
1090
0
{
1091
0
  TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
1092
0
  DateADT   dateVal = PG_GETARG_DATEADT(1);
1093
1094
0
  PG_RETURN_INT32(-date_cmp_timestamptz_internal(dateVal, dt1));
1095
0
}
1096
1097
/*
1098
 * in_range support function for date.
1099
 *
1100
 * We implement this by promoting the dates to timestamp (without time zone)
1101
 * and then using the timestamp-and-interval in_range function.
1102
 */
1103
Datum
1104
in_range_date_interval(PG_FUNCTION_ARGS)
1105
0
{
1106
0
  DateADT   val = PG_GETARG_DATEADT(0);
1107
0
  DateADT   base = PG_GETARG_DATEADT(1);
1108
0
  Interval   *offset = PG_GETARG_INTERVAL_P(2);
1109
0
  bool    sub = PG_GETARG_BOOL(3);
1110
0
  bool    less = PG_GETARG_BOOL(4);
1111
0
  Timestamp valStamp;
1112
0
  Timestamp baseStamp;
1113
1114
  /* XXX we could support out-of-range cases here, perhaps */
1115
0
  valStamp = date2timestamp(val);
1116
0
  baseStamp = date2timestamp(base);
1117
1118
0
  return DirectFunctionCall5(in_range_timestamp_interval,
1119
0
                 TimestampGetDatum(valStamp),
1120
0
                 TimestampGetDatum(baseStamp),
1121
0
                 IntervalPGetDatum(offset),
1122
0
                 BoolGetDatum(sub),
1123
0
                 BoolGetDatum(less));
1124
0
}
1125
1126
1127
/* extract_date()
1128
 * Extract specified field from date type.
1129
 */
1130
Datum
1131
extract_date(PG_FUNCTION_ARGS)
1132
0
{
1133
0
  text     *units = PG_GETARG_TEXT_PP(0);
1134
0
  DateADT   date = PG_GETARG_DATEADT(1);
1135
0
  int64   intresult;
1136
0
  int     type,
1137
0
        val;
1138
0
  char     *lowunits;
1139
0
  int     year,
1140
0
        mon,
1141
0
        mday;
1142
1143
0
  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1144
0
                      VARSIZE_ANY_EXHDR(units),
1145
0
                      false);
1146
1147
0
  type = DecodeUnits(0, lowunits, &val);
1148
0
  if (type == UNKNOWN_FIELD)
1149
0
    type = DecodeSpecial(0, lowunits, &val);
1150
1151
0
  if (DATE_NOT_FINITE(date) && (type == UNITS || type == RESERV))
1152
0
  {
1153
0
    switch (val)
1154
0
    {
1155
        /* Oscillating units */
1156
0
      case DTK_DAY:
1157
0
      case DTK_MONTH:
1158
0
      case DTK_QUARTER:
1159
0
      case DTK_WEEK:
1160
0
      case DTK_DOW:
1161
0
      case DTK_ISODOW:
1162
0
      case DTK_DOY:
1163
0
        PG_RETURN_NULL();
1164
0
        break;
1165
1166
        /* Monotonically-increasing units */
1167
0
      case DTK_YEAR:
1168
0
      case DTK_DECADE:
1169
0
      case DTK_CENTURY:
1170
0
      case DTK_MILLENNIUM:
1171
0
      case DTK_JULIAN:
1172
0
      case DTK_ISOYEAR:
1173
0
      case DTK_EPOCH:
1174
0
        if (DATE_IS_NOBEGIN(date))
1175
0
          PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
1176
0
                                      CStringGetDatum("-Infinity"),
1177
0
                                      ObjectIdGetDatum(InvalidOid),
1178
0
                                      Int32GetDatum(-1))));
1179
0
        else
1180
0
          PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
1181
0
                                      CStringGetDatum("Infinity"),
1182
0
                                      ObjectIdGetDatum(InvalidOid),
1183
0
                                      Int32GetDatum(-1))));
1184
0
      default:
1185
0
        ereport(ERROR,
1186
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1187
0
             errmsg("unit \"%s\" not supported for type %s",
1188
0
                lowunits, format_type_be(DATEOID))));
1189
0
    }
1190
0
  }
1191
0
  else if (type == UNITS)
1192
0
  {
1193
0
    j2date(date + POSTGRES_EPOCH_JDATE, &year, &mon, &mday);
1194
1195
0
    switch (val)
1196
0
    {
1197
0
      case DTK_DAY:
1198
0
        intresult = mday;
1199
0
        break;
1200
1201
0
      case DTK_MONTH:
1202
0
        intresult = mon;
1203
0
        break;
1204
1205
0
      case DTK_QUARTER:
1206
0
        intresult = (mon - 1) / 3 + 1;
1207
0
        break;
1208
1209
0
      case DTK_WEEK:
1210
0
        intresult = date2isoweek(year, mon, mday);
1211
0
        break;
1212
1213
0
      case DTK_YEAR:
1214
0
        if (year > 0)
1215
0
          intresult = year;
1216
0
        else
1217
          /* there is no year 0, just 1 BC and 1 AD */
1218
0
          intresult = year - 1;
1219
0
        break;
1220
1221
0
      case DTK_DECADE:
1222
        /* see comments in timestamp_part */
1223
0
        if (year >= 0)
1224
0
          intresult = year / 10;
1225
0
        else
1226
0
          intresult = -((8 - (year - 1)) / 10);
1227
0
        break;
1228
1229
0
      case DTK_CENTURY:
1230
        /* see comments in timestamp_part */
1231
0
        if (year > 0)
1232
0
          intresult = (year + 99) / 100;
1233
0
        else
1234
0
          intresult = -((99 - (year - 1)) / 100);
1235
0
        break;
1236
1237
0
      case DTK_MILLENNIUM:
1238
        /* see comments in timestamp_part */
1239
0
        if (year > 0)
1240
0
          intresult = (year + 999) / 1000;
1241
0
        else
1242
0
          intresult = -((999 - (year - 1)) / 1000);
1243
0
        break;
1244
1245
0
      case DTK_JULIAN:
1246
0
        intresult = date + POSTGRES_EPOCH_JDATE;
1247
0
        break;
1248
1249
0
      case DTK_ISOYEAR:
1250
0
        intresult = date2isoyear(year, mon, mday);
1251
        /* Adjust BC years */
1252
0
        if (intresult <= 0)
1253
0
          intresult -= 1;
1254
0
        break;
1255
1256
0
      case DTK_DOW:
1257
0
      case DTK_ISODOW:
1258
0
        intresult = j2day(date + POSTGRES_EPOCH_JDATE);
1259
0
        if (val == DTK_ISODOW && intresult == 0)
1260
0
          intresult = 7;
1261
0
        break;
1262
1263
0
      case DTK_DOY:
1264
0
        intresult = date2j(year, mon, mday) - date2j(year, 1, 1) + 1;
1265
0
        break;
1266
1267
0
      default:
1268
0
        ereport(ERROR,
1269
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1270
0
             errmsg("unit \"%s\" not supported for type %s",
1271
0
                lowunits, format_type_be(DATEOID))));
1272
0
        intresult = 0;
1273
0
    }
1274
0
  }
1275
0
  else if (type == RESERV)
1276
0
  {
1277
0
    switch (val)
1278
0
    {
1279
0
      case DTK_EPOCH:
1280
0
        intresult = ((int64) date + POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1281
0
        break;
1282
1283
0
      default:
1284
0
        ereport(ERROR,
1285
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1286
0
             errmsg("unit \"%s\" not supported for type %s",
1287
0
                lowunits, format_type_be(DATEOID))));
1288
0
        intresult = 0;
1289
0
    }
1290
0
  }
1291
0
  else
1292
0
  {
1293
0
    ereport(ERROR,
1294
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1295
0
         errmsg("unit \"%s\" not recognized for type %s",
1296
0
            lowunits, format_type_be(DATEOID))));
1297
0
    intresult = 0;
1298
0
  }
1299
1300
0
  PG_RETURN_NUMERIC(int64_to_numeric(intresult));
1301
0
}
1302
1303
1304
/* Add an interval to a date, giving a new date.
1305
 * Must handle both positive and negative intervals.
1306
 *
1307
 * We implement this by promoting the date to timestamp (without time zone)
1308
 * and then using the timestamp plus interval function.
1309
 */
1310
Datum
1311
date_pl_interval(PG_FUNCTION_ARGS)
1312
0
{
1313
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
1314
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
1315
0
  Timestamp dateStamp;
1316
1317
0
  dateStamp = date2timestamp(dateVal);
1318
1319
0
  return DirectFunctionCall2(timestamp_pl_interval,
1320
0
                 TimestampGetDatum(dateStamp),
1321
0
                 PointerGetDatum(span));
1322
0
}
1323
1324
/* Subtract an interval from a date, giving a new date.
1325
 * Must handle both positive and negative intervals.
1326
 *
1327
 * We implement this by promoting the date to timestamp (without time zone)
1328
 * and then using the timestamp minus interval function.
1329
 */
1330
Datum
1331
date_mi_interval(PG_FUNCTION_ARGS)
1332
0
{
1333
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
1334
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
1335
0
  Timestamp dateStamp;
1336
1337
0
  dateStamp = date2timestamp(dateVal);
1338
1339
0
  return DirectFunctionCall2(timestamp_mi_interval,
1340
0
                 TimestampGetDatum(dateStamp),
1341
0
                 PointerGetDatum(span));
1342
0
}
1343
1344
/* date_timestamp()
1345
 * Convert date to timestamp data type.
1346
 */
1347
Datum
1348
date_timestamp(PG_FUNCTION_ARGS)
1349
0
{
1350
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
1351
0
  Timestamp result;
1352
1353
0
  result = date2timestamp(dateVal);
1354
1355
0
  PG_RETURN_TIMESTAMP(result);
1356
0
}
1357
1358
/* timestamp_date()
1359
 * Convert timestamp to date data type.
1360
 */
1361
Datum
1362
timestamp_date(PG_FUNCTION_ARGS)
1363
0
{
1364
0
  Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1365
0
  DateADT   result;
1366
1367
0
  result = timestamp2date_opt_overflow(timestamp, NULL);
1368
0
  PG_RETURN_DATEADT(result);
1369
0
}
1370
1371
/*
1372
 * Convert timestamp to date.
1373
 *
1374
 * On successful conversion, *overflow is set to zero if it's not NULL.
1375
 *
1376
 * If the timestamp is finite but out of the valid range for date, then:
1377
 * if overflow is NULL, we throw an out-of-range error.
1378
 * if overflow is not NULL, we store +1 or -1 there to indicate the sign
1379
 * of the overflow, and return the appropriate date infinity.
1380
 *
1381
 * Note: given the ranges of the types, overflow is only possible at
1382
 * the minimum end of the range, but we don't assume that in this code.
1383
 */
1384
DateADT
1385
timestamp2date_opt_overflow(Timestamp timestamp, int *overflow)
1386
0
{
1387
0
  DateADT   result;
1388
0
  struct pg_tm tt,
1389
0
         *tm = &tt;
1390
0
  fsec_t    fsec;
1391
1392
0
  if (overflow)
1393
0
    *overflow = 0;
1394
1395
0
  if (TIMESTAMP_IS_NOBEGIN(timestamp))
1396
0
    DATE_NOBEGIN(result);
1397
0
  else if (TIMESTAMP_IS_NOEND(timestamp))
1398
0
    DATE_NOEND(result);
1399
0
  else
1400
0
  {
1401
0
    if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1402
0
    {
1403
0
      if (overflow)
1404
0
      {
1405
0
        if (timestamp < 0)
1406
0
        {
1407
0
          *overflow = -1;
1408
0
          DATE_NOBEGIN(result);
1409
0
        }
1410
0
        else
1411
0
        {
1412
0
          *overflow = 1;  /* not actually reachable */
1413
0
          DATE_NOEND(result);
1414
0
        }
1415
0
        return result;
1416
0
      }
1417
0
      ereport(ERROR,
1418
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1419
0
           errmsg("timestamp out of range")));
1420
0
    }
1421
1422
0
    result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1423
0
  }
1424
1425
0
  return result;
1426
0
}
1427
1428
1429
/* date_timestamptz()
1430
 * Convert date to timestamp with time zone data type.
1431
 */
1432
Datum
1433
date_timestamptz(PG_FUNCTION_ARGS)
1434
0
{
1435
0
  DateADT   dateVal = PG_GETARG_DATEADT(0);
1436
0
  TimestampTz result;
1437
1438
0
  result = date2timestamptz(dateVal);
1439
1440
0
  PG_RETURN_TIMESTAMP(result);
1441
0
}
1442
1443
1444
/* timestamptz_date()
1445
 * Convert timestamp with time zone to date data type.
1446
 */
1447
Datum
1448
timestamptz_date(PG_FUNCTION_ARGS)
1449
0
{
1450
0
  TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1451
0
  DateADT   result;
1452
1453
0
  result = timestamptz2date_opt_overflow(timestamp, NULL);
1454
0
  PG_RETURN_DATEADT(result);
1455
0
}
1456
1457
/*
1458
 * Convert timestamptz to date.
1459
 *
1460
 * On successful conversion, *overflow is set to zero if it's not NULL.
1461
 *
1462
 * If the timestamptz is finite but out of the valid range for date, then:
1463
 * if overflow is NULL, we throw an out-of-range error.
1464
 * if overflow is not NULL, we store +1 or -1 there to indicate the sign
1465
 * of the overflow, and return the appropriate date infinity.
1466
 *
1467
 * Note: given the ranges of the types, overflow is only possible at
1468
 * the minimum end of the range, but we don't assume that in this code.
1469
 */
1470
DateADT
1471
timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow)
1472
0
{
1473
0
  DateADT   result;
1474
0
  struct pg_tm tt,
1475
0
         *tm = &tt;
1476
0
  fsec_t    fsec;
1477
0
  int     tz;
1478
1479
0
  if (overflow)
1480
0
    *overflow = 0;
1481
1482
0
  if (TIMESTAMP_IS_NOBEGIN(timestamp))
1483
0
    DATE_NOBEGIN(result);
1484
0
  else if (TIMESTAMP_IS_NOEND(timestamp))
1485
0
    DATE_NOEND(result);
1486
0
  else
1487
0
  {
1488
0
    if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1489
0
    {
1490
0
      if (overflow)
1491
0
      {
1492
0
        if (timestamp < 0)
1493
0
        {
1494
0
          *overflow = -1;
1495
0
          DATE_NOBEGIN(result);
1496
0
        }
1497
0
        else
1498
0
        {
1499
0
          *overflow = 1;  /* not actually reachable */
1500
0
          DATE_NOEND(result);
1501
0
        }
1502
0
        return result;
1503
0
      }
1504
0
      ereport(ERROR,
1505
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1506
0
           errmsg("timestamp out of range")));
1507
0
    }
1508
1509
0
    result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1510
0
  }
1511
1512
0
  return result;
1513
0
}
1514
1515
1516
/*****************************************************************************
1517
 *   Time ADT
1518
 *****************************************************************************/
1519
1520
Datum
1521
time_in(PG_FUNCTION_ARGS)
1522
0
{
1523
0
  char     *str = PG_GETARG_CSTRING(0);
1524
#ifdef NOT_USED
1525
  Oid     typelem = PG_GETARG_OID(1);
1526
#endif
1527
0
  int32   typmod = PG_GETARG_INT32(2);
1528
0
  Node     *escontext = fcinfo->context;
1529
0
  TimeADT   result;
1530
0
  fsec_t    fsec;
1531
0
  struct pg_tm tt,
1532
0
         *tm = &tt;
1533
0
  int     tz;
1534
0
  int     nf;
1535
0
  int     dterr;
1536
0
  char    workbuf[MAXDATELEN + 1];
1537
0
  char     *field[MAXDATEFIELDS];
1538
0
  int     dtype;
1539
0
  int     ftype[MAXDATEFIELDS];
1540
0
  DateTimeErrorExtra extra;
1541
1542
0
  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1543
0
              field, ftype, MAXDATEFIELDS, &nf);
1544
0
  if (dterr == 0)
1545
0
    dterr = DecodeTimeOnly(field, ftype, nf,
1546
0
                 &dtype, tm, &fsec, &tz, &extra);
1547
0
  if (dterr != 0)
1548
0
  {
1549
0
    DateTimeParseError(dterr, &extra, str, "time", escontext);
1550
0
    PG_RETURN_NULL();
1551
0
  }
1552
1553
0
  tm2time(tm, fsec, &result);
1554
0
  AdjustTimeForTypmod(&result, typmod);
1555
1556
0
  PG_RETURN_TIMEADT(result);
1557
0
}
1558
1559
/* tm2time()
1560
 * Convert a tm structure to a time data type.
1561
 */
1562
int
1563
tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
1564
0
{
1565
0
  *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
1566
0
         * USECS_PER_SEC) + fsec;
1567
0
  return 0;
1568
0
}
1569
1570
/* time_overflows()
1571
 * Check to see if a broken-down time-of-day is out of range.
1572
 */
1573
bool
1574
time_overflows(int hour, int min, int sec, fsec_t fsec)
1575
0
{
1576
  /* Range-check the fields individually. */
1577
0
  if (hour < 0 || hour > HOURS_PER_DAY ||
1578
0
    min < 0 || min >= MINS_PER_HOUR ||
1579
0
    sec < 0 || sec > SECS_PER_MINUTE ||
1580
0
    fsec < 0 || fsec > USECS_PER_SEC)
1581
0
    return true;
1582
1583
  /*
1584
   * Because we allow, eg, hour = 24 or sec = 60, we must check separately
1585
   * that the total time value doesn't exceed 24:00:00.
1586
   */
1587
0
  if ((((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
1588
0
       + sec) * USECS_PER_SEC) + fsec) > USECS_PER_DAY)
1589
0
    return true;
1590
1591
0
  return false;
1592
0
}
1593
1594
/* float_time_overflows()
1595
 * Same, when we have seconds + fractional seconds as one "double" value.
1596
 */
1597
bool
1598
float_time_overflows(int hour, int min, double sec)
1599
0
{
1600
  /* Range-check the fields individually. */
1601
0
  if (hour < 0 || hour > HOURS_PER_DAY ||
1602
0
    min < 0 || min >= MINS_PER_HOUR)
1603
0
    return true;
1604
1605
  /*
1606
   * "sec", being double, requires extra care.  Cope with NaN, and round off
1607
   * before applying the range check to avoid unexpected errors due to
1608
   * imprecise input.  (We assume rint() behaves sanely with infinities.)
1609
   */
1610
0
  if (isnan(sec))
1611
0
    return true;
1612
0
  sec = rint(sec * USECS_PER_SEC);
1613
0
  if (sec < 0 || sec > SECS_PER_MINUTE * USECS_PER_SEC)
1614
0
    return true;
1615
1616
  /*
1617
   * Because we allow, eg, hour = 24 or sec = 60, we must check separately
1618
   * that the total time value doesn't exceed 24:00:00.  This must match the
1619
   * way that callers will convert the fields to a time.
1620
   */
1621
0
  if (((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
1622
0
      * USECS_PER_SEC) + (int64) sec) > USECS_PER_DAY)
1623
0
    return true;
1624
1625
0
  return false;
1626
0
}
1627
1628
1629
/* time2tm()
1630
 * Convert time data type to POSIX time structure.
1631
 *
1632
 * Note that only the hour/min/sec/fractional-sec fields are filled in.
1633
 */
1634
int
1635
time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
1636
0
{
1637
0
  tm->tm_hour = time / USECS_PER_HOUR;
1638
0
  time -= tm->tm_hour * USECS_PER_HOUR;
1639
0
  tm->tm_min = time / USECS_PER_MINUTE;
1640
0
  time -= tm->tm_min * USECS_PER_MINUTE;
1641
0
  tm->tm_sec = time / USECS_PER_SEC;
1642
0
  time -= tm->tm_sec * USECS_PER_SEC;
1643
0
  *fsec = time;
1644
0
  return 0;
1645
0
}
1646
1647
Datum
1648
time_out(PG_FUNCTION_ARGS)
1649
0
{
1650
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
1651
0
  char     *result;
1652
0
  struct pg_tm tt,
1653
0
         *tm = &tt;
1654
0
  fsec_t    fsec;
1655
0
  char    buf[MAXDATELEN + 1];
1656
1657
0
  time2tm(time, tm, &fsec);
1658
0
  EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
1659
1660
0
  result = pstrdup(buf);
1661
0
  PG_RETURN_CSTRING(result);
1662
0
}
1663
1664
/*
1665
 *    time_recv     - converts external binary format to time
1666
 */
1667
Datum
1668
time_recv(PG_FUNCTION_ARGS)
1669
0
{
1670
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
1671
1672
#ifdef NOT_USED
1673
  Oid     typelem = PG_GETARG_OID(1);
1674
#endif
1675
0
  int32   typmod = PG_GETARG_INT32(2);
1676
0
  TimeADT   result;
1677
1678
0
  result = pq_getmsgint64(buf);
1679
1680
0
  if (result < INT64CONST(0) || result > USECS_PER_DAY)
1681
0
    ereport(ERROR,
1682
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1683
0
         errmsg("time out of range")));
1684
1685
0
  AdjustTimeForTypmod(&result, typmod);
1686
1687
0
  PG_RETURN_TIMEADT(result);
1688
0
}
1689
1690
/*
1691
 *    time_send     - converts time to binary format
1692
 */
1693
Datum
1694
time_send(PG_FUNCTION_ARGS)
1695
0
{
1696
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
1697
0
  StringInfoData buf;
1698
1699
0
  pq_begintypsend(&buf);
1700
0
  pq_sendint64(&buf, time);
1701
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1702
0
}
1703
1704
Datum
1705
timetypmodin(PG_FUNCTION_ARGS)
1706
0
{
1707
0
  ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
1708
1709
0
  PG_RETURN_INT32(anytime_typmodin(false, ta));
1710
0
}
1711
1712
Datum
1713
timetypmodout(PG_FUNCTION_ARGS)
1714
0
{
1715
0
  int32   typmod = PG_GETARG_INT32(0);
1716
1717
0
  PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1718
0
}
1719
1720
/*
1721
 *    make_time     - time constructor
1722
 */
1723
Datum
1724
make_time(PG_FUNCTION_ARGS)
1725
0
{
1726
0
  int     tm_hour = PG_GETARG_INT32(0);
1727
0
  int     tm_min = PG_GETARG_INT32(1);
1728
0
  double    sec = PG_GETARG_FLOAT8(2);
1729
0
  TimeADT   time;
1730
1731
  /* Check for time overflow */
1732
0
  if (float_time_overflows(tm_hour, tm_min, sec))
1733
0
    ereport(ERROR,
1734
0
        (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
1735
0
         errmsg("time field value out of range: %d:%02d:%02g",
1736
0
            tm_hour, tm_min, sec)));
1737
1738
  /* This should match tm2time */
1739
0
  time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
1740
0
      * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
1741
1742
0
  PG_RETURN_TIMEADT(time);
1743
0
}
1744
1745
1746
/* time_support()
1747
 *
1748
 * Planner support function for the time_scale() and timetz_scale()
1749
 * length coercion functions (we need not distinguish them here).
1750
 */
1751
Datum
1752
time_support(PG_FUNCTION_ARGS)
1753
0
{
1754
0
  Node     *rawreq = (Node *) PG_GETARG_POINTER(0);
1755
0
  Node     *ret = NULL;
1756
1757
0
  if (IsA(rawreq, SupportRequestSimplify))
1758
0
  {
1759
0
    SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1760
1761
0
    ret = TemporalSimplify(MAX_TIME_PRECISION, (Node *) req->fcall);
1762
0
  }
1763
1764
0
  PG_RETURN_POINTER(ret);
1765
0
}
1766
1767
/* time_scale()
1768
 * Adjust time type for specified scale factor.
1769
 * Used by PostgreSQL type system to stuff columns.
1770
 */
1771
Datum
1772
time_scale(PG_FUNCTION_ARGS)
1773
0
{
1774
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
1775
0
  int32   typmod = PG_GETARG_INT32(1);
1776
0
  TimeADT   result;
1777
1778
0
  result = time;
1779
0
  AdjustTimeForTypmod(&result, typmod);
1780
1781
0
  PG_RETURN_TIMEADT(result);
1782
0
}
1783
1784
/* AdjustTimeForTypmod()
1785
 * Force the precision of the time value to a specified value.
1786
 * Uses *exactly* the same code as in AdjustTimestampForTypmod()
1787
 * but we make a separate copy because those types do not
1788
 * have a fundamental tie together but rather a coincidence of
1789
 * implementation. - thomas
1790
 */
1791
void
1792
AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1793
0
{
1794
0
  static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1795
0
    INT64CONST(1000000),
1796
0
    INT64CONST(100000),
1797
0
    INT64CONST(10000),
1798
0
    INT64CONST(1000),
1799
0
    INT64CONST(100),
1800
0
    INT64CONST(10),
1801
0
    INT64CONST(1)
1802
0
  };
1803
1804
0
  static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1805
0
    INT64CONST(500000),
1806
0
    INT64CONST(50000),
1807
0
    INT64CONST(5000),
1808
0
    INT64CONST(500),
1809
0
    INT64CONST(50),
1810
0
    INT64CONST(5),
1811
0
    INT64CONST(0)
1812
0
  };
1813
1814
0
  if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1815
0
  {
1816
0
    if (*time >= INT64CONST(0))
1817
0
      *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
1818
0
        TimeScales[typmod];
1819
0
    else
1820
0
      *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
1821
0
            TimeScales[typmod]);
1822
0
  }
1823
0
}
1824
1825
1826
Datum
1827
time_eq(PG_FUNCTION_ARGS)
1828
0
{
1829
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1830
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1831
1832
0
  PG_RETURN_BOOL(time1 == time2);
1833
0
}
1834
1835
Datum
1836
time_ne(PG_FUNCTION_ARGS)
1837
0
{
1838
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1839
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1840
1841
0
  PG_RETURN_BOOL(time1 != time2);
1842
0
}
1843
1844
Datum
1845
time_lt(PG_FUNCTION_ARGS)
1846
0
{
1847
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1848
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1849
1850
0
  PG_RETURN_BOOL(time1 < time2);
1851
0
}
1852
1853
Datum
1854
time_le(PG_FUNCTION_ARGS)
1855
0
{
1856
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1857
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1858
1859
0
  PG_RETURN_BOOL(time1 <= time2);
1860
0
}
1861
1862
Datum
1863
time_gt(PG_FUNCTION_ARGS)
1864
0
{
1865
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1866
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1867
1868
0
  PG_RETURN_BOOL(time1 > time2);
1869
0
}
1870
1871
Datum
1872
time_ge(PG_FUNCTION_ARGS)
1873
0
{
1874
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1875
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1876
1877
0
  PG_RETURN_BOOL(time1 >= time2);
1878
0
}
1879
1880
Datum
1881
time_cmp(PG_FUNCTION_ARGS)
1882
0
{
1883
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1884
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1885
1886
0
  if (time1 < time2)
1887
0
    PG_RETURN_INT32(-1);
1888
0
  if (time1 > time2)
1889
0
    PG_RETURN_INT32(1);
1890
0
  PG_RETURN_INT32(0);
1891
0
}
1892
1893
Datum
1894
time_hash(PG_FUNCTION_ARGS)
1895
0
{
1896
0
  return hashint8(fcinfo);
1897
0
}
1898
1899
Datum
1900
time_hash_extended(PG_FUNCTION_ARGS)
1901
0
{
1902
0
  return hashint8extended(fcinfo);
1903
0
}
1904
1905
Datum
1906
time_larger(PG_FUNCTION_ARGS)
1907
0
{
1908
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1909
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1910
1911
0
  PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1912
0
}
1913
1914
Datum
1915
time_smaller(PG_FUNCTION_ARGS)
1916
0
{
1917
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
1918
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
1919
1920
0
  PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1921
0
}
1922
1923
/* overlaps_time() --- implements the SQL OVERLAPS operator.
1924
 *
1925
 * Algorithm is per SQL spec.  This is much harder than you'd think
1926
 * because the spec requires us to deliver a non-null answer in some cases
1927
 * where some of the inputs are null.
1928
 */
1929
Datum
1930
overlaps_time(PG_FUNCTION_ARGS)
1931
0
{
1932
  /*
1933
   * The arguments are TimeADT, but we leave them as generic Datums to avoid
1934
   * dereferencing nulls (TimeADT is pass-by-reference!)
1935
   */
1936
0
  Datum   ts1 = PG_GETARG_DATUM(0);
1937
0
  Datum   te1 = PG_GETARG_DATUM(1);
1938
0
  Datum   ts2 = PG_GETARG_DATUM(2);
1939
0
  Datum   te2 = PG_GETARG_DATUM(3);
1940
0
  bool    ts1IsNull = PG_ARGISNULL(0);
1941
0
  bool    te1IsNull = PG_ARGISNULL(1);
1942
0
  bool    ts2IsNull = PG_ARGISNULL(2);
1943
0
  bool    te2IsNull = PG_ARGISNULL(3);
1944
1945
0
#define TIMEADT_GT(t1,t2) \
1946
0
  (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1947
0
#define TIMEADT_LT(t1,t2) \
1948
0
  (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1949
1950
  /*
1951
   * If both endpoints of interval 1 are null, the result is null (unknown).
1952
   * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1953
   * take ts1 as the lesser endpoint.
1954
   */
1955
0
  if (ts1IsNull)
1956
0
  {
1957
0
    if (te1IsNull)
1958
0
      PG_RETURN_NULL();
1959
    /* swap null for non-null */
1960
0
    ts1 = te1;
1961
0
    te1IsNull = true;
1962
0
  }
1963
0
  else if (!te1IsNull)
1964
0
  {
1965
0
    if (TIMEADT_GT(ts1, te1))
1966
0
    {
1967
0
      Datum   tt = ts1;
1968
1969
0
      ts1 = te1;
1970
0
      te1 = tt;
1971
0
    }
1972
0
  }
1973
1974
  /* Likewise for interval 2. */
1975
0
  if (ts2IsNull)
1976
0
  {
1977
0
    if (te2IsNull)
1978
0
      PG_RETURN_NULL();
1979
    /* swap null for non-null */
1980
0
    ts2 = te2;
1981
0
    te2IsNull = true;
1982
0
  }
1983
0
  else if (!te2IsNull)
1984
0
  {
1985
0
    if (TIMEADT_GT(ts2, te2))
1986
0
    {
1987
0
      Datum   tt = ts2;
1988
1989
0
      ts2 = te2;
1990
0
      te2 = tt;
1991
0
    }
1992
0
  }
1993
1994
  /*
1995
   * At this point neither ts1 nor ts2 is null, so we can consider three
1996
   * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1997
   */
1998
0
  if (TIMEADT_GT(ts1, ts2))
1999
0
  {
2000
    /*
2001
     * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2002
     * in the presence of nulls it's not quite completely so.
2003
     */
2004
0
    if (te2IsNull)
2005
0
      PG_RETURN_NULL();
2006
0
    if (TIMEADT_LT(ts1, te2))
2007
0
      PG_RETURN_BOOL(true);
2008
0
    if (te1IsNull)
2009
0
      PG_RETURN_NULL();
2010
2011
    /*
2012
     * If te1 is not null then we had ts1 <= te1 above, and we just found
2013
     * ts1 >= te2, hence te1 >= te2.
2014
     */
2015
0
    PG_RETURN_BOOL(false);
2016
0
  }
2017
0
  else if (TIMEADT_LT(ts1, ts2))
2018
0
  {
2019
    /* This case is ts2 < te1 OR te2 < te1 */
2020
0
    if (te1IsNull)
2021
0
      PG_RETURN_NULL();
2022
0
    if (TIMEADT_LT(ts2, te1))
2023
0
      PG_RETURN_BOOL(true);
2024
0
    if (te2IsNull)
2025
0
      PG_RETURN_NULL();
2026
2027
    /*
2028
     * If te2 is not null then we had ts2 <= te2 above, and we just found
2029
     * ts2 >= te1, hence te2 >= te1.
2030
     */
2031
0
    PG_RETURN_BOOL(false);
2032
0
  }
2033
0
  else
2034
0
  {
2035
    /*
2036
     * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2037
     * rather silly way of saying "true if both are nonnull, else null".
2038
     */
2039
0
    if (te1IsNull || te2IsNull)
2040
0
      PG_RETURN_NULL();
2041
0
    PG_RETURN_BOOL(true);
2042
0
  }
2043
2044
0
#undef TIMEADT_GT
2045
0
#undef TIMEADT_LT
2046
0
}
2047
2048
/* timestamp_time()
2049
 * Convert timestamp to time data type.
2050
 */
2051
Datum
2052
timestamp_time(PG_FUNCTION_ARGS)
2053
0
{
2054
0
  Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
2055
0
  TimeADT   result;
2056
0
  struct pg_tm tt,
2057
0
         *tm = &tt;
2058
0
  fsec_t    fsec;
2059
2060
0
  if (TIMESTAMP_NOT_FINITE(timestamp))
2061
0
    PG_RETURN_NULL();
2062
2063
0
  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
2064
0
    ereport(ERROR,
2065
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2066
0
         errmsg("timestamp out of range")));
2067
2068
  /*
2069
   * Could also do this with time = (timestamp / USECS_PER_DAY *
2070
   * USECS_PER_DAY) - timestamp;
2071
   */
2072
0
  result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
2073
0
        USECS_PER_SEC) + fsec;
2074
2075
0
  PG_RETURN_TIMEADT(result);
2076
0
}
2077
2078
/* timestamptz_time()
2079
 * Convert timestamptz to time data type.
2080
 */
2081
Datum
2082
timestamptz_time(PG_FUNCTION_ARGS)
2083
0
{
2084
0
  TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2085
0
  TimeADT   result;
2086
0
  struct pg_tm tt,
2087
0
         *tm = &tt;
2088
0
  int     tz;
2089
0
  fsec_t    fsec;
2090
2091
0
  if (TIMESTAMP_NOT_FINITE(timestamp))
2092
0
    PG_RETURN_NULL();
2093
2094
0
  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
2095
0
    ereport(ERROR,
2096
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2097
0
         errmsg("timestamp out of range")));
2098
2099
  /*
2100
   * Could also do this with time = (timestamp / USECS_PER_DAY *
2101
   * USECS_PER_DAY) - timestamp;
2102
   */
2103
0
  result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
2104
0
        USECS_PER_SEC) + fsec;
2105
2106
0
  PG_RETURN_TIMEADT(result);
2107
0
}
2108
2109
/* datetime_timestamp()
2110
 * Convert date and time to timestamp data type.
2111
 */
2112
Datum
2113
datetime_timestamp(PG_FUNCTION_ARGS)
2114
0
{
2115
0
  DateADT   date = PG_GETARG_DATEADT(0);
2116
0
  TimeADT   time = PG_GETARG_TIMEADT(1);
2117
0
  Timestamp result;
2118
2119
0
  result = date2timestamp(date);
2120
0
  if (!TIMESTAMP_NOT_FINITE(result))
2121
0
  {
2122
0
    result += time;
2123
0
    if (!IS_VALID_TIMESTAMP(result))
2124
0
      ereport(ERROR,
2125
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2126
0
           errmsg("timestamp out of range")));
2127
0
  }
2128
2129
0
  PG_RETURN_TIMESTAMP(result);
2130
0
}
2131
2132
/* time_interval()
2133
 * Convert time to interval data type.
2134
 */
2135
Datum
2136
time_interval(PG_FUNCTION_ARGS)
2137
0
{
2138
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
2139
0
  Interval   *result;
2140
2141
0
  result = (Interval *) palloc(sizeof(Interval));
2142
2143
0
  result->time = time;
2144
0
  result->day = 0;
2145
0
  result->month = 0;
2146
2147
0
  PG_RETURN_INTERVAL_P(result);
2148
0
}
2149
2150
/* interval_time()
2151
 * Convert interval to time data type.
2152
 *
2153
 * This is defined as producing the fractional-day portion of the interval.
2154
 * Therefore, we can just ignore the months field.  It is not real clear
2155
 * what to do with negative intervals, but we choose to subtract the floor,
2156
 * so that, say, '-2 hours' becomes '22:00:00'.
2157
 */
2158
Datum
2159
interval_time(PG_FUNCTION_ARGS)
2160
0
{
2161
0
  Interval   *span = PG_GETARG_INTERVAL_P(0);
2162
0
  TimeADT   result;
2163
2164
0
  if (INTERVAL_NOT_FINITE(span))
2165
0
    ereport(ERROR,
2166
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2167
0
         errmsg("cannot convert infinite interval to time")));
2168
2169
0
  result = span->time % USECS_PER_DAY;
2170
0
  if (result < 0)
2171
0
    result += USECS_PER_DAY;
2172
2173
0
  PG_RETURN_TIMEADT(result);
2174
0
}
2175
2176
/* time_mi_time()
2177
 * Subtract two times to produce an interval.
2178
 */
2179
Datum
2180
time_mi_time(PG_FUNCTION_ARGS)
2181
0
{
2182
0
  TimeADT   time1 = PG_GETARG_TIMEADT(0);
2183
0
  TimeADT   time2 = PG_GETARG_TIMEADT(1);
2184
0
  Interval   *result;
2185
2186
0
  result = (Interval *) palloc(sizeof(Interval));
2187
2188
0
  result->month = 0;
2189
0
  result->day = 0;
2190
0
  result->time = time1 - time2;
2191
2192
0
  PG_RETURN_INTERVAL_P(result);
2193
0
}
2194
2195
/* time_pl_interval()
2196
 * Add interval to time.
2197
 */
2198
Datum
2199
time_pl_interval(PG_FUNCTION_ARGS)
2200
0
{
2201
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
2202
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
2203
0
  TimeADT   result;
2204
2205
0
  if (INTERVAL_NOT_FINITE(span))
2206
0
    ereport(ERROR,
2207
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2208
0
         errmsg("cannot add infinite interval to time")));
2209
2210
0
  result = time + span->time;
2211
0
  result -= result / USECS_PER_DAY * USECS_PER_DAY;
2212
0
  if (result < INT64CONST(0))
2213
0
    result += USECS_PER_DAY;
2214
2215
0
  PG_RETURN_TIMEADT(result);
2216
0
}
2217
2218
/* time_mi_interval()
2219
 * Subtract interval from time.
2220
 */
2221
Datum
2222
time_mi_interval(PG_FUNCTION_ARGS)
2223
0
{
2224
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
2225
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
2226
0
  TimeADT   result;
2227
2228
0
  if (INTERVAL_NOT_FINITE(span))
2229
0
    ereport(ERROR,
2230
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2231
0
         errmsg("cannot subtract infinite interval from time")));
2232
2233
0
  result = time - span->time;
2234
0
  result -= result / USECS_PER_DAY * USECS_PER_DAY;
2235
0
  if (result < INT64CONST(0))
2236
0
    result += USECS_PER_DAY;
2237
2238
0
  PG_RETURN_TIMEADT(result);
2239
0
}
2240
2241
/*
2242
 * in_range support function for time.
2243
 */
2244
Datum
2245
in_range_time_interval(PG_FUNCTION_ARGS)
2246
0
{
2247
0
  TimeADT   val = PG_GETARG_TIMEADT(0);
2248
0
  TimeADT   base = PG_GETARG_TIMEADT(1);
2249
0
  Interval   *offset = PG_GETARG_INTERVAL_P(2);
2250
0
  bool    sub = PG_GETARG_BOOL(3);
2251
0
  bool    less = PG_GETARG_BOOL(4);
2252
0
  TimeADT   sum;
2253
2254
  /*
2255
   * Like time_pl_interval/time_mi_interval, we disregard the month and day
2256
   * fields of the offset.  So our test for negative should too.  This also
2257
   * catches -infinity, so we only need worry about +infinity below.
2258
   */
2259
0
  if (offset->time < 0)
2260
0
    ereport(ERROR,
2261
0
        (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2262
0
         errmsg("invalid preceding or following size in window function")));
2263
2264
  /*
2265
   * We can't use time_pl_interval/time_mi_interval here, because their
2266
   * wraparound behavior would give wrong (or at least undesirable) answers.
2267
   * Fortunately the equivalent non-wrapping behavior is trivial, except
2268
   * that adding an infinite (or very large) interval might cause integer
2269
   * overflow.  Subtraction cannot overflow here.
2270
   */
2271
0
  if (sub)
2272
0
    sum = base - offset->time;
2273
0
  else if (pg_add_s64_overflow(base, offset->time, &sum))
2274
0
    PG_RETURN_BOOL(less);
2275
2276
0
  if (less)
2277
0
    PG_RETURN_BOOL(val <= sum);
2278
0
  else
2279
0
    PG_RETURN_BOOL(val >= sum);
2280
0
}
2281
2282
2283
/* time_part() and extract_time()
2284
 * Extract specified field from time type.
2285
 */
2286
static Datum
2287
time_part_common(PG_FUNCTION_ARGS, bool retnumeric)
2288
0
{
2289
0
  text     *units = PG_GETARG_TEXT_PP(0);
2290
0
  TimeADT   time = PG_GETARG_TIMEADT(1);
2291
0
  int64   intresult;
2292
0
  int     type,
2293
0
        val;
2294
0
  char     *lowunits;
2295
2296
0
  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2297
0
                      VARSIZE_ANY_EXHDR(units),
2298
0
                      false);
2299
2300
0
  type = DecodeUnits(0, lowunits, &val);
2301
0
  if (type == UNKNOWN_FIELD)
2302
0
    type = DecodeSpecial(0, lowunits, &val);
2303
2304
0
  if (type == UNITS)
2305
0
  {
2306
0
    fsec_t    fsec;
2307
0
    struct pg_tm tt,
2308
0
           *tm = &tt;
2309
2310
0
    time2tm(time, tm, &fsec);
2311
2312
0
    switch (val)
2313
0
    {
2314
0
      case DTK_MICROSEC:
2315
0
        intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
2316
0
        break;
2317
2318
0
      case DTK_MILLISEC:
2319
0
        if (retnumeric)
2320
          /*---
2321
           * tm->tm_sec * 1000 + fsec / 1000
2322
           * = (tm->tm_sec * 1'000'000 + fsec) / 1000
2323
           */
2324
0
          PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
2325
0
        else
2326
0
          PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
2327
0
        break;
2328
2329
0
      case DTK_SECOND:
2330
0
        if (retnumeric)
2331
          /*---
2332
           * tm->tm_sec + fsec / 1'000'000
2333
           * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
2334
           */
2335
0
          PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
2336
0
        else
2337
0
          PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
2338
0
        break;
2339
2340
0
      case DTK_MINUTE:
2341
0
        intresult = tm->tm_min;
2342
0
        break;
2343
2344
0
      case DTK_HOUR:
2345
0
        intresult = tm->tm_hour;
2346
0
        break;
2347
2348
0
      case DTK_TZ:
2349
0
      case DTK_TZ_MINUTE:
2350
0
      case DTK_TZ_HOUR:
2351
0
      case DTK_DAY:
2352
0
      case DTK_MONTH:
2353
0
      case DTK_QUARTER:
2354
0
      case DTK_YEAR:
2355
0
      case DTK_DECADE:
2356
0
      case DTK_CENTURY:
2357
0
      case DTK_MILLENNIUM:
2358
0
      case DTK_ISOYEAR:
2359
0
      default:
2360
0
        ereport(ERROR,
2361
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2362
0
             errmsg("unit \"%s\" not supported for type %s",
2363
0
                lowunits, format_type_be(TIMEOID))));
2364
0
        intresult = 0;
2365
0
    }
2366
0
  }
2367
0
  else if (type == RESERV && val == DTK_EPOCH)
2368
0
  {
2369
0
    if (retnumeric)
2370
0
      PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time, 6));
2371
0
    else
2372
0
      PG_RETURN_FLOAT8(time / 1000000.0);
2373
0
  }
2374
0
  else
2375
0
  {
2376
0
    ereport(ERROR,
2377
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2378
0
         errmsg("unit \"%s\" not recognized for type %s",
2379
0
            lowunits, format_type_be(TIMEOID))));
2380
0
    intresult = 0;
2381
0
  }
2382
2383
0
  if (retnumeric)
2384
0
    PG_RETURN_NUMERIC(int64_to_numeric(intresult));
2385
0
  else
2386
0
    PG_RETURN_FLOAT8(intresult);
2387
0
}
2388
2389
Datum
2390
time_part(PG_FUNCTION_ARGS)
2391
0
{
2392
0
  return time_part_common(fcinfo, false);
2393
0
}
2394
2395
Datum
2396
extract_time(PG_FUNCTION_ARGS)
2397
0
{
2398
0
  return time_part_common(fcinfo, true);
2399
0
}
2400
2401
2402
/*****************************************************************************
2403
 *   Time With Time Zone ADT
2404
 *****************************************************************************/
2405
2406
/* tm2timetz()
2407
 * Convert a tm structure to a time data type.
2408
 */
2409
int
2410
tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
2411
0
{
2412
0
  result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
2413
0
          USECS_PER_SEC) + fsec;
2414
0
  result->zone = tz;
2415
2416
0
  return 0;
2417
0
}
2418
2419
Datum
2420
timetz_in(PG_FUNCTION_ARGS)
2421
0
{
2422
0
  char     *str = PG_GETARG_CSTRING(0);
2423
#ifdef NOT_USED
2424
  Oid     typelem = PG_GETARG_OID(1);
2425
#endif
2426
0
  int32   typmod = PG_GETARG_INT32(2);
2427
0
  Node     *escontext = fcinfo->context;
2428
0
  TimeTzADT  *result;
2429
0
  fsec_t    fsec;
2430
0
  struct pg_tm tt,
2431
0
         *tm = &tt;
2432
0
  int     tz;
2433
0
  int     nf;
2434
0
  int     dterr;
2435
0
  char    workbuf[MAXDATELEN + 1];
2436
0
  char     *field[MAXDATEFIELDS];
2437
0
  int     dtype;
2438
0
  int     ftype[MAXDATEFIELDS];
2439
0
  DateTimeErrorExtra extra;
2440
2441
0
  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
2442
0
              field, ftype, MAXDATEFIELDS, &nf);
2443
0
  if (dterr == 0)
2444
0
    dterr = DecodeTimeOnly(field, ftype, nf,
2445
0
                 &dtype, tm, &fsec, &tz, &extra);
2446
0
  if (dterr != 0)
2447
0
  {
2448
0
    DateTimeParseError(dterr, &extra, str, "time with time zone",
2449
0
               escontext);
2450
0
    PG_RETURN_NULL();
2451
0
  }
2452
2453
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2454
0
  tm2timetz(tm, fsec, tz, result);
2455
0
  AdjustTimeForTypmod(&(result->time), typmod);
2456
2457
0
  PG_RETURN_TIMETZADT_P(result);
2458
0
}
2459
2460
Datum
2461
timetz_out(PG_FUNCTION_ARGS)
2462
0
{
2463
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2464
0
  char     *result;
2465
0
  struct pg_tm tt,
2466
0
         *tm = &tt;
2467
0
  fsec_t    fsec;
2468
0
  int     tz;
2469
0
  char    buf[MAXDATELEN + 1];
2470
2471
0
  timetz2tm(time, tm, &fsec, &tz);
2472
0
  EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
2473
2474
0
  result = pstrdup(buf);
2475
0
  PG_RETURN_CSTRING(result);
2476
0
}
2477
2478
/*
2479
 *    timetz_recv     - converts external binary format to timetz
2480
 */
2481
Datum
2482
timetz_recv(PG_FUNCTION_ARGS)
2483
0
{
2484
0
  StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
2485
2486
#ifdef NOT_USED
2487
  Oid     typelem = PG_GETARG_OID(1);
2488
#endif
2489
0
  int32   typmod = PG_GETARG_INT32(2);
2490
0
  TimeTzADT  *result;
2491
2492
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2493
2494
0
  result->time = pq_getmsgint64(buf);
2495
2496
0
  if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
2497
0
    ereport(ERROR,
2498
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2499
0
         errmsg("time out of range")));
2500
2501
0
  result->zone = pq_getmsgint(buf, sizeof(result->zone));
2502
2503
  /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
2504
0
  if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
2505
0
    ereport(ERROR,
2506
0
        (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
2507
0
         errmsg("time zone displacement out of range")));
2508
2509
0
  AdjustTimeForTypmod(&(result->time), typmod);
2510
2511
0
  PG_RETURN_TIMETZADT_P(result);
2512
0
}
2513
2514
/*
2515
 *    timetz_send     - converts timetz to binary format
2516
 */
2517
Datum
2518
timetz_send(PG_FUNCTION_ARGS)
2519
0
{
2520
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2521
0
  StringInfoData buf;
2522
2523
0
  pq_begintypsend(&buf);
2524
0
  pq_sendint64(&buf, time->time);
2525
0
  pq_sendint32(&buf, time->zone);
2526
0
  PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2527
0
}
2528
2529
Datum
2530
timetztypmodin(PG_FUNCTION_ARGS)
2531
0
{
2532
0
  ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
2533
2534
0
  PG_RETURN_INT32(anytime_typmodin(true, ta));
2535
0
}
2536
2537
Datum
2538
timetztypmodout(PG_FUNCTION_ARGS)
2539
0
{
2540
0
  int32   typmod = PG_GETARG_INT32(0);
2541
2542
0
  PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
2543
0
}
2544
2545
2546
/* timetz2tm()
2547
 * Convert TIME WITH TIME ZONE data type to POSIX time structure.
2548
 */
2549
int
2550
timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
2551
0
{
2552
0
  TimeOffset  trem = time->time;
2553
2554
0
  tm->tm_hour = trem / USECS_PER_HOUR;
2555
0
  trem -= tm->tm_hour * USECS_PER_HOUR;
2556
0
  tm->tm_min = trem / USECS_PER_MINUTE;
2557
0
  trem -= tm->tm_min * USECS_PER_MINUTE;
2558
0
  tm->tm_sec = trem / USECS_PER_SEC;
2559
0
  *fsec = trem - tm->tm_sec * USECS_PER_SEC;
2560
2561
0
  if (tzp != NULL)
2562
0
    *tzp = time->zone;
2563
2564
0
  return 0;
2565
0
}
2566
2567
/* timetz_scale()
2568
 * Adjust time type for specified scale factor.
2569
 * Used by PostgreSQL type system to stuff columns.
2570
 */
2571
Datum
2572
timetz_scale(PG_FUNCTION_ARGS)
2573
0
{
2574
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2575
0
  int32   typmod = PG_GETARG_INT32(1);
2576
0
  TimeTzADT  *result;
2577
2578
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2579
2580
0
  result->time = time->time;
2581
0
  result->zone = time->zone;
2582
2583
0
  AdjustTimeForTypmod(&(result->time), typmod);
2584
2585
0
  PG_RETURN_TIMETZADT_P(result);
2586
0
}
2587
2588
2589
static int
2590
timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
2591
0
{
2592
0
  TimeOffset  t1,
2593
0
        t2;
2594
2595
  /* Primary sort is by true (GMT-equivalent) time */
2596
0
  t1 = time1->time + (time1->zone * USECS_PER_SEC);
2597
0
  t2 = time2->time + (time2->zone * USECS_PER_SEC);
2598
2599
0
  if (t1 > t2)
2600
0
    return 1;
2601
0
  if (t1 < t2)
2602
0
    return -1;
2603
2604
  /*
2605
   * If same GMT time, sort by timezone; we only want to say that two
2606
   * timetz's are equal if both the time and zone parts are equal.
2607
   */
2608
0
  if (time1->zone > time2->zone)
2609
0
    return 1;
2610
0
  if (time1->zone < time2->zone)
2611
0
    return -1;
2612
2613
0
  return 0;
2614
0
}
2615
2616
Datum
2617
timetz_eq(PG_FUNCTION_ARGS)
2618
0
{
2619
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2620
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2621
2622
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2623
0
}
2624
2625
Datum
2626
timetz_ne(PG_FUNCTION_ARGS)
2627
0
{
2628
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2629
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2630
2631
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2632
0
}
2633
2634
Datum
2635
timetz_lt(PG_FUNCTION_ARGS)
2636
0
{
2637
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2638
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2639
2640
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2641
0
}
2642
2643
Datum
2644
timetz_le(PG_FUNCTION_ARGS)
2645
0
{
2646
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2647
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2648
2649
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2650
0
}
2651
2652
Datum
2653
timetz_gt(PG_FUNCTION_ARGS)
2654
0
{
2655
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2656
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2657
2658
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2659
0
}
2660
2661
Datum
2662
timetz_ge(PG_FUNCTION_ARGS)
2663
0
{
2664
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2665
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2666
2667
0
  PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2668
0
}
2669
2670
Datum
2671
timetz_cmp(PG_FUNCTION_ARGS)
2672
0
{
2673
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2674
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2675
2676
0
  PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2677
0
}
2678
2679
Datum
2680
timetz_hash(PG_FUNCTION_ARGS)
2681
0
{
2682
0
  TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
2683
0
  uint32    thash;
2684
2685
  /*
2686
   * To avoid any problems with padding bytes in the struct, we figure the
2687
   * field hashes separately and XOR them.
2688
   */
2689
0
  thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2690
0
                         Int64GetDatumFast(key->time)));
2691
0
  thash ^= DatumGetUInt32(hash_uint32(key->zone));
2692
0
  PG_RETURN_UINT32(thash);
2693
0
}
2694
2695
Datum
2696
timetz_hash_extended(PG_FUNCTION_ARGS)
2697
0
{
2698
0
  TimeTzADT  *key = PG_GETARG_TIMETZADT_P(0);
2699
0
  Datum   seed = PG_GETARG_DATUM(1);
2700
0
  uint64    thash;
2701
2702
  /* Same approach as timetz_hash */
2703
0
  thash = DatumGetUInt64(DirectFunctionCall2(hashint8extended,
2704
0
                         Int64GetDatumFast(key->time),
2705
0
                         seed));
2706
0
  thash ^= DatumGetUInt64(hash_uint32_extended(key->zone,
2707
0
                         DatumGetInt64(seed)));
2708
0
  PG_RETURN_UINT64(thash);
2709
0
}
2710
2711
Datum
2712
timetz_larger(PG_FUNCTION_ARGS)
2713
0
{
2714
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2715
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2716
0
  TimeTzADT  *result;
2717
2718
0
  if (timetz_cmp_internal(time1, time2) > 0)
2719
0
    result = time1;
2720
0
  else
2721
0
    result = time2;
2722
0
  PG_RETURN_TIMETZADT_P(result);
2723
0
}
2724
2725
Datum
2726
timetz_smaller(PG_FUNCTION_ARGS)
2727
0
{
2728
0
  TimeTzADT  *time1 = PG_GETARG_TIMETZADT_P(0);
2729
0
  TimeTzADT  *time2 = PG_GETARG_TIMETZADT_P(1);
2730
0
  TimeTzADT  *result;
2731
2732
0
  if (timetz_cmp_internal(time1, time2) < 0)
2733
0
    result = time1;
2734
0
  else
2735
0
    result = time2;
2736
0
  PG_RETURN_TIMETZADT_P(result);
2737
0
}
2738
2739
/* timetz_pl_interval()
2740
 * Add interval to timetz.
2741
 */
2742
Datum
2743
timetz_pl_interval(PG_FUNCTION_ARGS)
2744
0
{
2745
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2746
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
2747
0
  TimeTzADT  *result;
2748
2749
0
  if (INTERVAL_NOT_FINITE(span))
2750
0
    ereport(ERROR,
2751
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2752
0
         errmsg("cannot add infinite interval to time")));
2753
2754
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2755
2756
0
  result->time = time->time + span->time;
2757
0
  result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2758
0
  if (result->time < INT64CONST(0))
2759
0
    result->time += USECS_PER_DAY;
2760
2761
0
  result->zone = time->zone;
2762
2763
0
  PG_RETURN_TIMETZADT_P(result);
2764
0
}
2765
2766
/* timetz_mi_interval()
2767
 * Subtract interval from timetz.
2768
 */
2769
Datum
2770
timetz_mi_interval(PG_FUNCTION_ARGS)
2771
0
{
2772
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
2773
0
  Interval   *span = PG_GETARG_INTERVAL_P(1);
2774
0
  TimeTzADT  *result;
2775
2776
0
  if (INTERVAL_NOT_FINITE(span))
2777
0
    ereport(ERROR,
2778
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2779
0
         errmsg("cannot subtract infinite interval from time")));
2780
2781
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2782
2783
0
  result->time = time->time - span->time;
2784
0
  result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
2785
0
  if (result->time < INT64CONST(0))
2786
0
    result->time += USECS_PER_DAY;
2787
2788
0
  result->zone = time->zone;
2789
2790
0
  PG_RETURN_TIMETZADT_P(result);
2791
0
}
2792
2793
/*
2794
 * in_range support function for timetz.
2795
 */
2796
Datum
2797
in_range_timetz_interval(PG_FUNCTION_ARGS)
2798
0
{
2799
0
  TimeTzADT  *val = PG_GETARG_TIMETZADT_P(0);
2800
0
  TimeTzADT  *base = PG_GETARG_TIMETZADT_P(1);
2801
0
  Interval   *offset = PG_GETARG_INTERVAL_P(2);
2802
0
  bool    sub = PG_GETARG_BOOL(3);
2803
0
  bool    less = PG_GETARG_BOOL(4);
2804
0
  TimeTzADT sum;
2805
2806
  /*
2807
   * Like timetz_pl_interval/timetz_mi_interval, we disregard the month and
2808
   * day fields of the offset.  So our test for negative should too. This
2809
   * also catches -infinity, so we only need worry about +infinity below.
2810
   */
2811
0
  if (offset->time < 0)
2812
0
    ereport(ERROR,
2813
0
        (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2814
0
         errmsg("invalid preceding or following size in window function")));
2815
2816
  /*
2817
   * We can't use timetz_pl_interval/timetz_mi_interval here, because their
2818
   * wraparound behavior would give wrong (or at least undesirable) answers.
2819
   * Fortunately the equivalent non-wrapping behavior is trivial, except
2820
   * that adding an infinite (or very large) interval might cause integer
2821
   * overflow.  Subtraction cannot overflow here.
2822
   */
2823
0
  if (sub)
2824
0
    sum.time = base->time - offset->time;
2825
0
  else if (pg_add_s64_overflow(base->time, offset->time, &sum.time))
2826
0
    PG_RETURN_BOOL(less);
2827
0
  sum.zone = base->zone;
2828
2829
0
  if (less)
2830
0
    PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) <= 0);
2831
0
  else
2832
0
    PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) >= 0);
2833
0
}
2834
2835
/* overlaps_timetz() --- implements the SQL OVERLAPS operator.
2836
 *
2837
 * Algorithm is per SQL spec.  This is much harder than you'd think
2838
 * because the spec requires us to deliver a non-null answer in some cases
2839
 * where some of the inputs are null.
2840
 */
2841
Datum
2842
overlaps_timetz(PG_FUNCTION_ARGS)
2843
0
{
2844
  /*
2845
   * The arguments are TimeTzADT *, but we leave them as generic Datums for
2846
   * convenience of notation --- and to avoid dereferencing nulls.
2847
   */
2848
0
  Datum   ts1 = PG_GETARG_DATUM(0);
2849
0
  Datum   te1 = PG_GETARG_DATUM(1);
2850
0
  Datum   ts2 = PG_GETARG_DATUM(2);
2851
0
  Datum   te2 = PG_GETARG_DATUM(3);
2852
0
  bool    ts1IsNull = PG_ARGISNULL(0);
2853
0
  bool    te1IsNull = PG_ARGISNULL(1);
2854
0
  bool    ts2IsNull = PG_ARGISNULL(2);
2855
0
  bool    te2IsNull = PG_ARGISNULL(3);
2856
2857
0
#define TIMETZ_GT(t1,t2) \
2858
0
  DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2859
0
#define TIMETZ_LT(t1,t2) \
2860
0
  DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2861
2862
  /*
2863
   * If both endpoints of interval 1 are null, the result is null (unknown).
2864
   * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2865
   * take ts1 as the lesser endpoint.
2866
   */
2867
0
  if (ts1IsNull)
2868
0
  {
2869
0
    if (te1IsNull)
2870
0
      PG_RETURN_NULL();
2871
    /* swap null for non-null */
2872
0
    ts1 = te1;
2873
0
    te1IsNull = true;
2874
0
  }
2875
0
  else if (!te1IsNull)
2876
0
  {
2877
0
    if (TIMETZ_GT(ts1, te1))
2878
0
    {
2879
0
      Datum   tt = ts1;
2880
2881
0
      ts1 = te1;
2882
0
      te1 = tt;
2883
0
    }
2884
0
  }
2885
2886
  /* Likewise for interval 2. */
2887
0
  if (ts2IsNull)
2888
0
  {
2889
0
    if (te2IsNull)
2890
0
      PG_RETURN_NULL();
2891
    /* swap null for non-null */
2892
0
    ts2 = te2;
2893
0
    te2IsNull = true;
2894
0
  }
2895
0
  else if (!te2IsNull)
2896
0
  {
2897
0
    if (TIMETZ_GT(ts2, te2))
2898
0
    {
2899
0
      Datum   tt = ts2;
2900
2901
0
      ts2 = te2;
2902
0
      te2 = tt;
2903
0
    }
2904
0
  }
2905
2906
  /*
2907
   * At this point neither ts1 nor ts2 is null, so we can consider three
2908
   * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2909
   */
2910
0
  if (TIMETZ_GT(ts1, ts2))
2911
0
  {
2912
    /*
2913
     * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2914
     * in the presence of nulls it's not quite completely so.
2915
     */
2916
0
    if (te2IsNull)
2917
0
      PG_RETURN_NULL();
2918
0
    if (TIMETZ_LT(ts1, te2))
2919
0
      PG_RETURN_BOOL(true);
2920
0
    if (te1IsNull)
2921
0
      PG_RETURN_NULL();
2922
2923
    /*
2924
     * If te1 is not null then we had ts1 <= te1 above, and we just found
2925
     * ts1 >= te2, hence te1 >= te2.
2926
     */
2927
0
    PG_RETURN_BOOL(false);
2928
0
  }
2929
0
  else if (TIMETZ_LT(ts1, ts2))
2930
0
  {
2931
    /* This case is ts2 < te1 OR te2 < te1 */
2932
0
    if (te1IsNull)
2933
0
      PG_RETURN_NULL();
2934
0
    if (TIMETZ_LT(ts2, te1))
2935
0
      PG_RETURN_BOOL(true);
2936
0
    if (te2IsNull)
2937
0
      PG_RETURN_NULL();
2938
2939
    /*
2940
     * If te2 is not null then we had ts2 <= te2 above, and we just found
2941
     * ts2 >= te1, hence te2 >= te1.
2942
     */
2943
0
    PG_RETURN_BOOL(false);
2944
0
  }
2945
0
  else
2946
0
  {
2947
    /*
2948
     * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2949
     * rather silly way of saying "true if both are nonnull, else null".
2950
     */
2951
0
    if (te1IsNull || te2IsNull)
2952
0
      PG_RETURN_NULL();
2953
0
    PG_RETURN_BOOL(true);
2954
0
  }
2955
2956
0
#undef TIMETZ_GT
2957
0
#undef TIMETZ_LT
2958
0
}
2959
2960
2961
Datum
2962
timetz_time(PG_FUNCTION_ARGS)
2963
0
{
2964
0
  TimeTzADT  *timetz = PG_GETARG_TIMETZADT_P(0);
2965
0
  TimeADT   result;
2966
2967
  /* swallow the time zone and just return the time */
2968
0
  result = timetz->time;
2969
2970
0
  PG_RETURN_TIMEADT(result);
2971
0
}
2972
2973
2974
Datum
2975
time_timetz(PG_FUNCTION_ARGS)
2976
0
{
2977
0
  TimeADT   time = PG_GETARG_TIMEADT(0);
2978
0
  TimeTzADT  *result;
2979
0
  struct pg_tm tt,
2980
0
         *tm = &tt;
2981
0
  fsec_t    fsec;
2982
0
  int     tz;
2983
2984
0
  GetCurrentDateTime(tm);
2985
0
  time2tm(time, tm, &fsec);
2986
0
  tz = DetermineTimeZoneOffset(tm, session_timezone);
2987
2988
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2989
2990
0
  result->time = time;
2991
0
  result->zone = tz;
2992
2993
0
  PG_RETURN_TIMETZADT_P(result);
2994
0
}
2995
2996
2997
/* timestamptz_timetz()
2998
 * Convert timestamp to timetz data type.
2999
 */
3000
Datum
3001
timestamptz_timetz(PG_FUNCTION_ARGS)
3002
0
{
3003
0
  TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
3004
0
  TimeTzADT  *result;
3005
0
  struct pg_tm tt,
3006
0
         *tm = &tt;
3007
0
  int     tz;
3008
0
  fsec_t    fsec;
3009
3010
0
  if (TIMESTAMP_NOT_FINITE(timestamp))
3011
0
    PG_RETURN_NULL();
3012
3013
0
  if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
3014
0
    ereport(ERROR,
3015
0
        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3016
0
         errmsg("timestamp out of range")));
3017
3018
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
3019
3020
0
  tm2timetz(tm, fsec, tz, result);
3021
3022
0
  PG_RETURN_TIMETZADT_P(result);
3023
0
}
3024
3025
3026
/* datetimetz_timestamptz()
3027
 * Convert date and timetz to timestamp with time zone data type.
3028
 * Timestamp is stored in GMT, so add the time zone
3029
 * stored with the timetz to the result.
3030
 * - thomas 2000-03-10
3031
 */
3032
Datum
3033
datetimetz_timestamptz(PG_FUNCTION_ARGS)
3034
0
{
3035
0
  DateADT   date = PG_GETARG_DATEADT(0);
3036
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
3037
0
  TimestampTz result;
3038
3039
0
  if (DATE_IS_NOBEGIN(date))
3040
0
    TIMESTAMP_NOBEGIN(result);
3041
0
  else if (DATE_IS_NOEND(date))
3042
0
    TIMESTAMP_NOEND(result);
3043
0
  else
3044
0
  {
3045
    /*
3046
     * Date's range is wider than timestamp's, so check for boundaries.
3047
     * Since dates have the same minimum values as timestamps, only upper
3048
     * boundary need be checked for overflow.
3049
     */
3050
0
    if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
3051
0
      ereport(ERROR,
3052
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3053
0
           errmsg("date out of range for timestamp")));
3054
0
    result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
3055
3056
    /*
3057
     * Since it is possible to go beyond allowed timestamptz range because
3058
     * of time zone, check for allowed timestamp range after adding tz.
3059
     */
3060
0
    if (!IS_VALID_TIMESTAMP(result))
3061
0
      ereport(ERROR,
3062
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3063
0
           errmsg("date out of range for timestamp")));
3064
0
  }
3065
3066
0
  PG_RETURN_TIMESTAMP(result);
3067
0
}
3068
3069
3070
/* timetz_part() and extract_timetz()
3071
 * Extract specified field from time type.
3072
 */
3073
static Datum
3074
timetz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
3075
0
{
3076
0
  text     *units = PG_GETARG_TEXT_PP(0);
3077
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
3078
0
  int64   intresult;
3079
0
  int     type,
3080
0
        val;
3081
0
  char     *lowunits;
3082
3083
0
  lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3084
0
                      VARSIZE_ANY_EXHDR(units),
3085
0
                      false);
3086
3087
0
  type = DecodeUnits(0, lowunits, &val);
3088
0
  if (type == UNKNOWN_FIELD)
3089
0
    type = DecodeSpecial(0, lowunits, &val);
3090
3091
0
  if (type == UNITS)
3092
0
  {
3093
0
    int     tz;
3094
0
    fsec_t    fsec;
3095
0
    struct pg_tm tt,
3096
0
           *tm = &tt;
3097
3098
0
    timetz2tm(time, tm, &fsec, &tz);
3099
3100
0
    switch (val)
3101
0
    {
3102
0
      case DTK_TZ:
3103
0
        intresult = -tz;
3104
0
        break;
3105
3106
0
      case DTK_TZ_MINUTE:
3107
0
        intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
3108
0
        break;
3109
3110
0
      case DTK_TZ_HOUR:
3111
0
        intresult = -tz / SECS_PER_HOUR;
3112
0
        break;
3113
3114
0
      case DTK_MICROSEC:
3115
0
        intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
3116
0
        break;
3117
3118
0
      case DTK_MILLISEC:
3119
0
        if (retnumeric)
3120
          /*---
3121
           * tm->tm_sec * 1000 + fsec / 1000
3122
           * = (tm->tm_sec * 1'000'000 + fsec) / 1000
3123
           */
3124
0
          PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
3125
0
        else
3126
0
          PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
3127
0
        break;
3128
3129
0
      case DTK_SECOND:
3130
0
        if (retnumeric)
3131
          /*---
3132
           * tm->tm_sec + fsec / 1'000'000
3133
           * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
3134
           */
3135
0
          PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
3136
0
        else
3137
0
          PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
3138
0
        break;
3139
3140
0
      case DTK_MINUTE:
3141
0
        intresult = tm->tm_min;
3142
0
        break;
3143
3144
0
      case DTK_HOUR:
3145
0
        intresult = tm->tm_hour;
3146
0
        break;
3147
3148
0
      case DTK_DAY:
3149
0
      case DTK_MONTH:
3150
0
      case DTK_QUARTER:
3151
0
      case DTK_YEAR:
3152
0
      case DTK_DECADE:
3153
0
      case DTK_CENTURY:
3154
0
      case DTK_MILLENNIUM:
3155
0
      default:
3156
0
        ereport(ERROR,
3157
0
            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3158
0
             errmsg("unit \"%s\" not supported for type %s",
3159
0
                lowunits, format_type_be(TIMETZOID))));
3160
0
        intresult = 0;
3161
0
    }
3162
0
  }
3163
0
  else if (type == RESERV && val == DTK_EPOCH)
3164
0
  {
3165
0
    if (retnumeric)
3166
      /*---
3167
       * time->time / 1'000'000 + time->zone
3168
       * = (time->time + time->zone * 1'000'000) / 1'000'000
3169
       */
3170
0
      PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time->time + time->zone * INT64CONST(1000000), 6));
3171
0
    else
3172
0
      PG_RETURN_FLOAT8(time->time / 1000000.0 + time->zone);
3173
0
  }
3174
0
  else
3175
0
  {
3176
0
    ereport(ERROR,
3177
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3178
0
         errmsg("unit \"%s\" not recognized for type %s",
3179
0
            lowunits, format_type_be(TIMETZOID))));
3180
0
    intresult = 0;
3181
0
  }
3182
3183
0
  if (retnumeric)
3184
0
    PG_RETURN_NUMERIC(int64_to_numeric(intresult));
3185
0
  else
3186
0
    PG_RETURN_FLOAT8(intresult);
3187
0
}
3188
3189
3190
Datum
3191
timetz_part(PG_FUNCTION_ARGS)
3192
0
{
3193
0
  return timetz_part_common(fcinfo, false);
3194
0
}
3195
3196
Datum
3197
extract_timetz(PG_FUNCTION_ARGS)
3198
0
{
3199
0
  return timetz_part_common(fcinfo, true);
3200
0
}
3201
3202
/* timetz_zone()
3203
 * Encode time with time zone type with specified time zone.
3204
 * Applies DST rules as of the transaction start time.
3205
 */
3206
Datum
3207
timetz_zone(PG_FUNCTION_ARGS)
3208
0
{
3209
0
  text     *zone = PG_GETARG_TEXT_PP(0);
3210
0
  TimeTzADT  *t = PG_GETARG_TIMETZADT_P(1);
3211
0
  TimeTzADT  *result;
3212
0
  int     tz;
3213
0
  char    tzname[TZ_STRLEN_MAX + 1];
3214
0
  int     type,
3215
0
        val;
3216
0
  pg_tz    *tzp;
3217
3218
  /*
3219
   * Look up the requested timezone.
3220
   */
3221
0
  text_to_cstring_buffer(zone, tzname, sizeof(tzname));
3222
3223
0
  type = DecodeTimezoneName(tzname, &val, &tzp);
3224
3225
0
  if (type == TZNAME_FIXED_OFFSET)
3226
0
  {
3227
    /* fixed-offset abbreviation */
3228
0
    tz = -val;
3229
0
  }
3230
0
  else if (type == TZNAME_DYNTZ)
3231
0
  {
3232
    /* dynamic-offset abbreviation, resolve using transaction start time */
3233
0
    TimestampTz now = GetCurrentTransactionStartTimestamp();
3234
0
    int     isdst;
3235
3236
0
    tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
3237
0
  }
3238
0
  else
3239
0
  {
3240
    /* Get the offset-from-GMT that is valid now for the zone name */
3241
0
    TimestampTz now = GetCurrentTransactionStartTimestamp();
3242
0
    struct pg_tm tm;
3243
0
    fsec_t    fsec;
3244
3245
0
    if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
3246
0
      ereport(ERROR,
3247
0
          (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3248
0
           errmsg("timestamp out of range")));
3249
0
  }
3250
3251
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
3252
3253
0
  result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
3254
  /* C99 modulo has the wrong sign convention for negative input */
3255
0
  while (result->time < INT64CONST(0))
3256
0
    result->time += USECS_PER_DAY;
3257
0
  if (result->time >= USECS_PER_DAY)
3258
0
    result->time %= USECS_PER_DAY;
3259
3260
0
  result->zone = tz;
3261
3262
0
  PG_RETURN_TIMETZADT_P(result);
3263
0
}
3264
3265
/* timetz_izone()
3266
 * Encode time with time zone type with specified time interval as time zone.
3267
 */
3268
Datum
3269
timetz_izone(PG_FUNCTION_ARGS)
3270
0
{
3271
0
  Interval   *zone = PG_GETARG_INTERVAL_P(0);
3272
0
  TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
3273
0
  TimeTzADT  *result;
3274
0
  int     tz;
3275
3276
0
  if (INTERVAL_NOT_FINITE(zone))
3277
0
    ereport(ERROR,
3278
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3279
0
         errmsg("interval time zone \"%s\" must be finite",
3280
0
            DatumGetCString(DirectFunctionCall1(interval_out,
3281
0
                              PointerGetDatum(zone))))));
3282
3283
0
  if (zone->month != 0 || zone->day != 0)
3284
0
    ereport(ERROR,
3285
0
        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3286
0
         errmsg("interval time zone \"%s\" must not include months or days",
3287
0
            DatumGetCString(DirectFunctionCall1(interval_out,
3288
0
                              PointerGetDatum(zone))))));
3289
3290
0
  tz = -(zone->time / USECS_PER_SEC);
3291
3292
0
  result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
3293
3294
0
  result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
3295
  /* C99 modulo has the wrong sign convention for negative input */
3296
0
  while (result->time < INT64CONST(0))
3297
0
    result->time += USECS_PER_DAY;
3298
0
  if (result->time >= USECS_PER_DAY)
3299
0
    result->time %= USECS_PER_DAY;
3300
3301
0
  result->zone = tz;
3302
3303
0
  PG_RETURN_TIMETZADT_P(result);
3304
0
}
3305
3306
/* timetz_at_local()
3307
 *
3308
 * Unlike for timestamp[tz]_at_local, the type for timetz does not flip between
3309
 * time with/without time zone, so we cannot just call the conversion function.
3310
 */
3311
Datum
3312
timetz_at_local(PG_FUNCTION_ARGS)
3313
0
{
3314
0
  Datum   time = PG_GETARG_DATUM(0);
3315
0
  const char *tzn = pg_get_timezone_name(session_timezone);
3316
0
  Datum   zone = PointerGetDatum(cstring_to_text(tzn));
3317
3318
0
  return DirectFunctionCall2(timetz_zone, zone, time);
3319
0
}