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