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