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