YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

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