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