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