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