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