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