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