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