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