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