Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * timestamp.c
4 : * Functions for the built-in SQL types "timestamp" and "interval".
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/timestamp.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include <ctype.h>
19 : #include <math.h>
20 : #include <limits.h>
21 : #include <sys/time.h>
22 :
23 : #include "access/xact.h"
24 : #include "catalog/pg_type.h"
25 : #include "common/int.h"
26 : #include "common/int128.h"
27 : #include "funcapi.h"
28 : #include "libpq/pqformat.h"
29 : #include "miscadmin.h"
30 : #include "nodes/nodeFuncs.h"
31 : #include "nodes/supportnodes.h"
32 : #include "optimizer/optimizer.h"
33 : #include "parser/scansup.h"
34 : #include "utils/array.h"
35 : #include "utils/builtins.h"
36 : #include "utils/date.h"
37 : #include "utils/datetime.h"
38 : #include "utils/float.h"
39 : #include "utils/numeric.h"
40 : #include "utils/skipsupport.h"
41 : #include "utils/sortsupport.h"
42 :
43 : /*
44 : * gcc's -ffast-math switch breaks routines that expect exact results from
45 : * expressions like timeval / SECS_PER_HOUR, where timeval is double.
46 : */
47 : #ifdef __FAST_MATH__
48 : #error -ffast-math is known to break this code
49 : #endif
50 :
51 : /* Set at postmaster start */
52 : TimestampTz PgStartTime;
53 :
54 : /* Set at configuration reload */
55 : TimestampTz PgReloadTime;
56 :
57 : typedef struct
58 : {
59 : Timestamp current;
60 : Timestamp finish;
61 : Interval step;
62 : int step_sign;
63 : } generate_series_timestamp_fctx;
64 :
65 : typedef struct
66 : {
67 : TimestampTz current;
68 : TimestampTz finish;
69 : Interval step;
70 : int step_sign;
71 : pg_tz *attimezone;
72 : } generate_series_timestamptz_fctx;
73 :
74 : /*
75 : * The transition datatype for interval aggregates is declared as internal.
76 : * It's a pointer to an IntervalAggState allocated in the aggregate context.
77 : */
78 : typedef struct IntervalAggState
79 : {
80 : int64 N; /* count of finite intervals processed */
81 : Interval sumX; /* sum of finite intervals processed */
82 : /* These counts are *not* included in N! Use IA_TOTAL_COUNT() as needed */
83 : int64 pInfcount; /* count of +infinity intervals */
84 : int64 nInfcount; /* count of -infinity intervals */
85 : } IntervalAggState;
86 :
87 : #define IA_TOTAL_COUNT(ia) \
88 : ((ia)->N + (ia)->pInfcount + (ia)->nInfcount)
89 :
90 : static TimeOffset time2t(const int hour, const int min, const int sec, const fsec_t fsec);
91 : static Timestamp dt2local(Timestamp dt, int timezone);
92 : static bool AdjustIntervalForTypmod(Interval *interval, int32 typmod,
93 : Node *escontext);
94 : static TimestampTz timestamp2timestamptz(Timestamp timestamp);
95 : static Timestamp timestamptz2timestamp(TimestampTz timestamp);
96 :
97 : static void EncodeSpecialInterval(const Interval *interval, char *str);
98 : static void interval_um_internal(const Interval *interval, Interval *result);
99 :
100 : /* common code for timestamptypmodin and timestamptztypmodin */
101 : static int32
102 78 : anytimestamp_typmodin(bool istz, ArrayType *ta)
103 : {
104 : int32 *tl;
105 : int n;
106 :
107 78 : tl = ArrayGetIntegerTypmods(ta, &n);
108 :
109 : /*
110 : * we're not too tense about good error message here because grammar
111 : * shouldn't allow wrong number of modifiers for TIMESTAMP
112 : */
113 78 : if (n != 1)
114 0 : ereport(ERROR,
115 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
116 : errmsg("invalid type modifier")));
117 :
118 78 : return anytimestamp_typmod_check(istz, tl[0]);
119 : }
120 :
121 : /* exported so parse_expr.c can use it */
122 : int32
123 364 : anytimestamp_typmod_check(bool istz, int32 typmod)
124 : {
125 364 : if (typmod < 0)
126 0 : ereport(ERROR,
127 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
128 : errmsg("TIMESTAMP(%d)%s precision must not be negative",
129 : typmod, (istz ? " WITH TIME ZONE" : ""))));
130 364 : if (typmod > MAX_TIMESTAMP_PRECISION)
131 : {
132 18 : ereport(WARNING,
133 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
134 : errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
135 : typmod, (istz ? " WITH TIME ZONE" : ""),
136 : MAX_TIMESTAMP_PRECISION)));
137 18 : typmod = MAX_TIMESTAMP_PRECISION;
138 : }
139 :
140 364 : return typmod;
141 : }
142 :
143 : /* common code for timestamptypmodout and timestamptztypmodout */
144 : static char *
145 10 : anytimestamp_typmodout(bool istz, int32 typmod)
146 : {
147 10 : const char *tz = istz ? " with time zone" : " without time zone";
148 :
149 10 : if (typmod >= 0)
150 10 : return psprintf("(%d)%s", (int) typmod, tz);
151 : else
152 0 : return pstrdup(tz);
153 : }
154 :
155 :
156 : /*****************************************************************************
157 : * USER I/O ROUTINES *
158 : *****************************************************************************/
159 :
160 : /* timestamp_in()
161 : * Convert a string to internal form.
162 : */
163 : Datum
164 8826 : timestamp_in(PG_FUNCTION_ARGS)
165 : {
166 8826 : char *str = PG_GETARG_CSTRING(0);
167 : #ifdef NOT_USED
168 : Oid typelem = PG_GETARG_OID(1);
169 : #endif
170 8826 : int32 typmod = PG_GETARG_INT32(2);
171 8826 : Node *escontext = fcinfo->context;
172 : Timestamp result;
173 : fsec_t fsec;
174 : struct pg_tm tt,
175 8826 : *tm = &tt;
176 : int tz;
177 : int dtype;
178 : int nf;
179 : int dterr;
180 : char *field[MAXDATEFIELDS];
181 : int ftype[MAXDATEFIELDS];
182 : char workbuf[MAXDATELEN + MAXDATEFIELDS];
183 : DateTimeErrorExtra extra;
184 :
185 8826 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
186 : field, ftype, MAXDATEFIELDS, &nf);
187 8826 : if (dterr == 0)
188 8826 : dterr = DecodeDateTime(field, ftype, nf,
189 : &dtype, tm, &fsec, &tz, &extra);
190 8826 : if (dterr != 0)
191 : {
192 57 : DateTimeParseError(dterr, &extra, str, "timestamp", escontext);
193 12 : PG_RETURN_NULL();
194 : }
195 :
196 8769 : switch (dtype)
197 : {
198 8574 : case DTK_DATE:
199 8574 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
200 9 : ereturn(escontext, (Datum) 0,
201 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
202 : errmsg("timestamp out of range: \"%s\"", str)));
203 8565 : break;
204 :
205 12 : case DTK_EPOCH:
206 12 : result = SetEpochTimestamp();
207 12 : break;
208 :
209 106 : case DTK_LATE:
210 106 : TIMESTAMP_NOEND(result);
211 106 : break;
212 :
213 77 : case DTK_EARLY:
214 77 : TIMESTAMP_NOBEGIN(result);
215 77 : break;
216 :
217 0 : default:
218 0 : elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
219 : dtype, str);
220 : TIMESTAMP_NOEND(result);
221 : }
222 :
223 8760 : AdjustTimestampForTypmod(&result, typmod, escontext);
224 :
225 8760 : PG_RETURN_TIMESTAMP(result);
226 : }
227 :
228 : /* timestamp_out()
229 : * Convert a timestamp to external form.
230 : */
231 : Datum
232 21729 : timestamp_out(PG_FUNCTION_ARGS)
233 : {
234 21729 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
235 : char *result;
236 : struct pg_tm tt,
237 21729 : *tm = &tt;
238 : fsec_t fsec;
239 : char buf[MAXDATELEN + 1];
240 :
241 21729 : if (TIMESTAMP_NOT_FINITE(timestamp))
242 265 : EncodeSpecialTimestamp(timestamp, buf);
243 21464 : else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
244 21464 : EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
245 : else
246 0 : ereport(ERROR,
247 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
248 : errmsg("timestamp out of range")));
249 :
250 21729 : result = pstrdup(buf);
251 21729 : PG_RETURN_CSTRING(result);
252 : }
253 :
254 : /*
255 : * timestamp_recv - converts external binary format to timestamp
256 : */
257 : Datum
258 0 : timestamp_recv(PG_FUNCTION_ARGS)
259 : {
260 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
261 :
262 : #ifdef NOT_USED
263 : Oid typelem = PG_GETARG_OID(1);
264 : #endif
265 0 : int32 typmod = PG_GETARG_INT32(2);
266 : Timestamp timestamp;
267 : struct pg_tm tt,
268 0 : *tm = &tt;
269 : fsec_t fsec;
270 :
271 0 : timestamp = (Timestamp) pq_getmsgint64(buf);
272 :
273 : /* range check: see if timestamp_out would like it */
274 0 : if (TIMESTAMP_NOT_FINITE(timestamp))
275 : /* ok */ ;
276 0 : else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
277 0 : !IS_VALID_TIMESTAMP(timestamp))
278 0 : ereport(ERROR,
279 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
280 : errmsg("timestamp out of range")));
281 :
282 0 : AdjustTimestampForTypmod(×tamp, typmod, NULL);
283 :
284 0 : PG_RETURN_TIMESTAMP(timestamp);
285 : }
286 :
287 : /*
288 : * timestamp_send - converts timestamp to binary format
289 : */
290 : Datum
291 0 : timestamp_send(PG_FUNCTION_ARGS)
292 : {
293 0 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
294 : StringInfoData buf;
295 :
296 0 : pq_begintypsend(&buf);
297 0 : pq_sendint64(&buf, timestamp);
298 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
299 : }
300 :
301 : Datum
302 18 : timestamptypmodin(PG_FUNCTION_ARGS)
303 : {
304 18 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
305 :
306 18 : PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
307 : }
308 :
309 : Datum
310 5 : timestamptypmodout(PG_FUNCTION_ARGS)
311 : {
312 5 : int32 typmod = PG_GETARG_INT32(0);
313 :
314 5 : PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
315 : }
316 :
317 :
318 : /*
319 : * timestamp_support()
320 : *
321 : * Planner support function for the timestamp_scale() and timestamptz_scale()
322 : * length coercion functions (we need not distinguish them here).
323 : */
324 : Datum
325 12 : timestamp_support(PG_FUNCTION_ARGS)
326 : {
327 12 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
328 12 : Node *ret = NULL;
329 :
330 12 : if (IsA(rawreq, SupportRequestSimplify))
331 : {
332 6 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
333 :
334 6 : ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall);
335 : }
336 :
337 12 : PG_RETURN_POINTER(ret);
338 : }
339 :
340 : /* timestamp_scale()
341 : * Adjust time type for specified scale factor.
342 : * Used by PostgreSQL type system to stuff columns.
343 : */
344 : Datum
345 31086 : timestamp_scale(PG_FUNCTION_ARGS)
346 : {
347 31086 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
348 31086 : int32 typmod = PG_GETARG_INT32(1);
349 : Timestamp result;
350 :
351 31086 : result = timestamp;
352 :
353 31086 : AdjustTimestampForTypmod(&result, typmod, NULL);
354 :
355 31086 : PG_RETURN_TIMESTAMP(result);
356 : }
357 :
358 : /*
359 : * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
360 : * Works for either timestamp or timestamptz.
361 : *
362 : * Returns true on success, false on failure (if escontext points to an
363 : * ErrorSaveContext; otherwise errors are thrown).
364 : */
365 : bool
366 62929 : AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
367 : {
368 : static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION + 1] = {
369 : INT64CONST(1000000),
370 : INT64CONST(100000),
371 : INT64CONST(10000),
372 : INT64CONST(1000),
373 : INT64CONST(100),
374 : INT64CONST(10),
375 : INT64CONST(1)
376 : };
377 :
378 : static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
379 : INT64CONST(500000),
380 : INT64CONST(50000),
381 : INT64CONST(5000),
382 : INT64CONST(500),
383 : INT64CONST(50),
384 : INT64CONST(5),
385 : INT64CONST(0)
386 : };
387 :
388 62929 : if (!TIMESTAMP_NOT_FINITE(*time)
389 62523 : && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
390 : {
391 31615 : if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
392 0 : ereturn(escontext, false,
393 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
394 : errmsg("timestamp(%d) precision must be between %d and %d",
395 : typmod, 0, MAX_TIMESTAMP_PRECISION)));
396 :
397 31615 : if (*time >= INT64CONST(0))
398 : {
399 31294 : *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
400 31294 : TimestampScales[typmod];
401 : }
402 : else
403 : {
404 321 : *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
405 321 : * TimestampScales[typmod]);
406 : }
407 : }
408 :
409 62929 : return true;
410 : }
411 :
412 : /* timestamptz_in()
413 : * Convert a string to internal form.
414 : */
415 : Datum
416 20701 : timestamptz_in(PG_FUNCTION_ARGS)
417 : {
418 20701 : char *str = PG_GETARG_CSTRING(0);
419 : #ifdef NOT_USED
420 : Oid typelem = PG_GETARG_OID(1);
421 : #endif
422 20701 : int32 typmod = PG_GETARG_INT32(2);
423 20701 : Node *escontext = fcinfo->context;
424 : TimestampTz result;
425 : fsec_t fsec;
426 : struct pg_tm tt,
427 20701 : *tm = &tt;
428 : int tz;
429 : int dtype;
430 : int nf;
431 : int dterr;
432 : char *field[MAXDATEFIELDS];
433 : int ftype[MAXDATEFIELDS];
434 : char workbuf[MAXDATELEN + MAXDATEFIELDS];
435 : DateTimeErrorExtra extra;
436 :
437 20701 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
438 : field, ftype, MAXDATEFIELDS, &nf);
439 20701 : if (dterr == 0)
440 20701 : dterr = DecodeDateTime(field, ftype, nf,
441 : &dtype, tm, &fsec, &tz, &extra);
442 20701 : if (dterr != 0)
443 : {
444 63 : DateTimeParseError(dterr, &extra, str, "timestamp with time zone",
445 : escontext);
446 12 : PG_RETURN_NULL();
447 : }
448 :
449 20638 : switch (dtype)
450 : {
451 20421 : case DTK_DATE:
452 20421 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
453 12 : ereturn(escontext, (Datum) 0,
454 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
455 : errmsg("timestamp out of range: \"%s\"", str)));
456 20409 : break;
457 :
458 6 : case DTK_EPOCH:
459 6 : result = SetEpochTimestamp();
460 6 : break;
461 :
462 127 : case DTK_LATE:
463 127 : TIMESTAMP_NOEND(result);
464 127 : break;
465 :
466 84 : case DTK_EARLY:
467 84 : TIMESTAMP_NOBEGIN(result);
468 84 : break;
469 :
470 0 : default:
471 0 : elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
472 : dtype, str);
473 : TIMESTAMP_NOEND(result);
474 : }
475 :
476 20626 : AdjustTimestampForTypmod(&result, typmod, escontext);
477 :
478 20626 : PG_RETURN_TIMESTAMPTZ(result);
479 : }
480 :
481 : /*
482 : * Try to parse a timezone specification, and return its timezone offset value
483 : * if it's acceptable. Otherwise, an error is thrown.
484 : *
485 : * Note: some code paths update tm->tm_isdst, and some don't; current callers
486 : * don't care, so we don't bother being consistent.
487 : */
488 : static int
489 99 : parse_sane_timezone(struct pg_tm *tm, text *zone)
490 : {
491 : char tzname[TZ_STRLEN_MAX + 1];
492 : int dterr;
493 : int tz;
494 :
495 99 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
496 :
497 : /*
498 : * Look up the requested timezone. First we try to interpret it as a
499 : * numeric timezone specification; if DecodeTimezone decides it doesn't
500 : * like the format, we try timezone abbreviations and names.
501 : *
502 : * Note pg_tzset happily parses numeric input that DecodeTimezone would
503 : * reject. To avoid having it accept input that would otherwise be seen
504 : * as invalid, it's enough to disallow having a digit in the first
505 : * position of our input string.
506 : */
507 99 : if (isdigit((unsigned char) *tzname))
508 3 : ereport(ERROR,
509 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
510 : errmsg("invalid input syntax for type %s: \"%s\"",
511 : "numeric time zone", tzname),
512 : errhint("Numeric time zones must have \"-\" or \"+\" as first character.")));
513 :
514 96 : dterr = DecodeTimezone(tzname, &tz);
515 96 : if (dterr != 0)
516 : {
517 : int type,
518 : val;
519 : pg_tz *tzp;
520 :
521 42 : if (dterr == DTERR_TZDISP_OVERFLOW)
522 6 : ereport(ERROR,
523 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
524 : errmsg("numeric time zone \"%s\" out of range", tzname)));
525 36 : else if (dterr != DTERR_BAD_FORMAT)
526 0 : ereport(ERROR,
527 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
528 : errmsg("time zone \"%s\" not recognized", tzname)));
529 :
530 36 : type = DecodeTimezoneName(tzname, &val, &tzp);
531 :
532 33 : if (type == TZNAME_FIXED_OFFSET)
533 : {
534 : /* fixed-offset abbreviation */
535 6 : tz = -val;
536 : }
537 27 : else if (type == TZNAME_DYNTZ)
538 : {
539 : /* dynamic-offset abbreviation, resolve using specified time */
540 6 : tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
541 : }
542 : else
543 : {
544 : /* full zone name */
545 21 : tz = DetermineTimeZoneOffset(tm, tzp);
546 : }
547 : }
548 :
549 87 : return tz;
550 : }
551 :
552 : /*
553 : * Look up the requested timezone, returning a pg_tz struct.
554 : *
555 : * This is the same as DecodeTimezoneNameToTz, but starting with a text Datum.
556 : */
557 : static pg_tz *
558 48 : lookup_timezone(text *zone)
559 : {
560 : char tzname[TZ_STRLEN_MAX + 1];
561 :
562 48 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
563 :
564 48 : return DecodeTimezoneNameToTz(tzname);
565 : }
566 :
567 : /*
568 : * make_timestamp_internal
569 : * workhorse for make_timestamp and make_timestamptz
570 : */
571 : static Timestamp
572 117 : make_timestamp_internal(int year, int month, int day,
573 : int hour, int min, double sec)
574 : {
575 : struct pg_tm tm;
576 : TimeOffset date;
577 : TimeOffset time;
578 : int dterr;
579 117 : bool bc = false;
580 : Timestamp result;
581 :
582 117 : tm.tm_year = year;
583 117 : tm.tm_mon = month;
584 117 : tm.tm_mday = day;
585 :
586 : /* Handle negative years as BC */
587 117 : if (tm.tm_year < 0)
588 : {
589 3 : bc = true;
590 3 : tm.tm_year = -tm.tm_year;
591 : }
592 :
593 117 : dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
594 :
595 117 : if (dterr != 0)
596 3 : ereport(ERROR,
597 : (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
598 : errmsg("date field value out of range: %d-%02d-%02d",
599 : year, month, day)));
600 :
601 114 : if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
602 0 : ereport(ERROR,
603 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
604 : errmsg("date out of range: %d-%02d-%02d",
605 : year, month, day)));
606 :
607 114 : date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
608 :
609 : /* Check for time overflow */
610 114 : if (float_time_overflows(hour, min, sec))
611 0 : ereport(ERROR,
612 : (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
613 : errmsg("time field value out of range: %d:%02d:%02g",
614 : hour, min, sec)));
615 :
616 : /* This should match tm2time */
617 114 : time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
618 114 : * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
619 :
620 114 : if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, &result) ||
621 : pg_add_s64_overflow(result, time, &result)))
622 0 : ereport(ERROR,
623 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
624 : errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
625 : year, month, day,
626 : hour, min, sec)));
627 :
628 : /* final range check catches just-out-of-range timestamps */
629 114 : if (!IS_VALID_TIMESTAMP(result))
630 0 : ereport(ERROR,
631 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
632 : errmsg("timestamp out of range: %d-%02d-%02d %d:%02d:%02g",
633 : year, month, day,
634 : hour, min, sec)));
635 :
636 114 : return result;
637 : }
638 :
639 : /*
640 : * make_timestamp() - timestamp constructor
641 : */
642 : Datum
643 12 : make_timestamp(PG_FUNCTION_ARGS)
644 : {
645 12 : int32 year = PG_GETARG_INT32(0);
646 12 : int32 month = PG_GETARG_INT32(1);
647 12 : int32 mday = PG_GETARG_INT32(2);
648 12 : int32 hour = PG_GETARG_INT32(3);
649 12 : int32 min = PG_GETARG_INT32(4);
650 12 : float8 sec = PG_GETARG_FLOAT8(5);
651 : Timestamp result;
652 :
653 12 : result = make_timestamp_internal(year, month, mday,
654 : hour, min, sec);
655 :
656 9 : PG_RETURN_TIMESTAMP(result);
657 : }
658 :
659 : /*
660 : * make_timestamptz() - timestamp with time zone constructor
661 : */
662 : Datum
663 6 : make_timestamptz(PG_FUNCTION_ARGS)
664 : {
665 6 : int32 year = PG_GETARG_INT32(0);
666 6 : int32 month = PG_GETARG_INT32(1);
667 6 : int32 mday = PG_GETARG_INT32(2);
668 6 : int32 hour = PG_GETARG_INT32(3);
669 6 : int32 min = PG_GETARG_INT32(4);
670 6 : float8 sec = PG_GETARG_FLOAT8(5);
671 : Timestamp result;
672 :
673 6 : result = make_timestamp_internal(year, month, mday,
674 : hour, min, sec);
675 :
676 6 : PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
677 : }
678 :
679 : /*
680 : * Construct a timestamp with time zone.
681 : * As above, but the time zone is specified as seventh argument.
682 : */
683 : Datum
684 99 : make_timestamptz_at_timezone(PG_FUNCTION_ARGS)
685 : {
686 99 : int32 year = PG_GETARG_INT32(0);
687 99 : int32 month = PG_GETARG_INT32(1);
688 99 : int32 mday = PG_GETARG_INT32(2);
689 99 : int32 hour = PG_GETARG_INT32(3);
690 99 : int32 min = PG_GETARG_INT32(4);
691 99 : float8 sec = PG_GETARG_FLOAT8(5);
692 99 : text *zone = PG_GETARG_TEXT_PP(6);
693 : TimestampTz result;
694 : Timestamp timestamp;
695 : struct pg_tm tt;
696 : int tz;
697 : fsec_t fsec;
698 :
699 99 : timestamp = make_timestamp_internal(year, month, mday,
700 : hour, min, sec);
701 :
702 99 : if (timestamp2tm(timestamp, NULL, &tt, &fsec, NULL, NULL) != 0)
703 0 : ereport(ERROR,
704 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
705 : errmsg("timestamp out of range")));
706 :
707 99 : tz = parse_sane_timezone(&tt, zone);
708 :
709 87 : result = dt2local(timestamp, -tz);
710 :
711 87 : if (!IS_VALID_TIMESTAMP(result))
712 0 : ereport(ERROR,
713 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
714 : errmsg("timestamp out of range")));
715 :
716 87 : PG_RETURN_TIMESTAMPTZ(result);
717 : }
718 :
719 : /*
720 : * to_timestamp(double precision)
721 : * Convert UNIX epoch to timestamptz.
722 : */
723 : Datum
724 27 : float8_timestamptz(PG_FUNCTION_ARGS)
725 : {
726 27 : float8 seconds = PG_GETARG_FLOAT8(0);
727 : TimestampTz result;
728 :
729 : /* Deal with NaN and infinite inputs ... */
730 27 : if (isnan(seconds))
731 3 : ereport(ERROR,
732 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
733 : errmsg("timestamp cannot be NaN")));
734 :
735 24 : if (isinf(seconds))
736 : {
737 6 : if (seconds < 0)
738 3 : TIMESTAMP_NOBEGIN(result);
739 : else
740 3 : TIMESTAMP_NOEND(result);
741 : }
742 : else
743 : {
744 : /* Out of range? */
745 18 : if (seconds <
746 : (float8) SECS_PER_DAY * (DATETIME_MIN_JULIAN - UNIX_EPOCH_JDATE)
747 18 : || seconds >=
748 : (float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
749 0 : ereport(ERROR,
750 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
751 : errmsg("timestamp out of range: \"%g\"", seconds)));
752 :
753 : /* Convert UNIX epoch to Postgres epoch */
754 18 : seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
755 :
756 18 : seconds = rint(seconds * USECS_PER_SEC);
757 18 : result = (int64) seconds;
758 :
759 : /* Recheck in case roundoff produces something just out of range */
760 18 : if (!IS_VALID_TIMESTAMP(result))
761 0 : ereport(ERROR,
762 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
763 : errmsg("timestamp out of range: \"%g\"",
764 : PG_GETARG_FLOAT8(0))));
765 : }
766 :
767 24 : PG_RETURN_TIMESTAMP(result);
768 : }
769 :
770 : /* timestamptz_out()
771 : * Convert a timestamp to external form.
772 : */
773 : Datum
774 35465 : timestamptz_out(PG_FUNCTION_ARGS)
775 : {
776 35465 : TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
777 : char *result;
778 : int tz;
779 : struct pg_tm tt,
780 35465 : *tm = &tt;
781 : fsec_t fsec;
782 : const char *tzn;
783 : char buf[MAXDATELEN + 1];
784 :
785 35465 : if (TIMESTAMP_NOT_FINITE(dt))
786 374 : EncodeSpecialTimestamp(dt, buf);
787 35091 : else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
788 35091 : EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
789 : else
790 0 : ereport(ERROR,
791 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
792 : errmsg("timestamp out of range")));
793 :
794 35465 : result = pstrdup(buf);
795 35465 : PG_RETURN_CSTRING(result);
796 : }
797 :
798 : /*
799 : * timestamptz_recv - converts external binary format to timestamptz
800 : */
801 : Datum
802 0 : timestamptz_recv(PG_FUNCTION_ARGS)
803 : {
804 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
805 :
806 : #ifdef NOT_USED
807 : Oid typelem = PG_GETARG_OID(1);
808 : #endif
809 0 : int32 typmod = PG_GETARG_INT32(2);
810 : TimestampTz timestamp;
811 : int tz;
812 : struct pg_tm tt,
813 0 : *tm = &tt;
814 : fsec_t fsec;
815 :
816 0 : timestamp = (TimestampTz) pq_getmsgint64(buf);
817 :
818 : /* range check: see if timestamptz_out would like it */
819 0 : if (TIMESTAMP_NOT_FINITE(timestamp))
820 : /* ok */ ;
821 0 : else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
822 0 : !IS_VALID_TIMESTAMP(timestamp))
823 0 : ereport(ERROR,
824 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
825 : errmsg("timestamp out of range")));
826 :
827 0 : AdjustTimestampForTypmod(×tamp, typmod, NULL);
828 :
829 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
830 : }
831 :
832 : /*
833 : * timestamptz_send - converts timestamptz to binary format
834 : */
835 : Datum
836 0 : timestamptz_send(PG_FUNCTION_ARGS)
837 : {
838 0 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
839 : StringInfoData buf;
840 :
841 0 : pq_begintypsend(&buf);
842 0 : pq_sendint64(&buf, timestamp);
843 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
844 : }
845 :
846 : Datum
847 60 : timestamptztypmodin(PG_FUNCTION_ARGS)
848 : {
849 60 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
850 :
851 60 : PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
852 : }
853 :
854 : Datum
855 5 : timestamptztypmodout(PG_FUNCTION_ARGS)
856 : {
857 5 : int32 typmod = PG_GETARG_INT32(0);
858 :
859 5 : PG_RETURN_CSTRING(anytimestamp_typmodout(true, typmod));
860 : }
861 :
862 :
863 : /* timestamptz_scale()
864 : * Adjust time type for specified scale factor.
865 : * Used by PostgreSQL type system to stuff columns.
866 : */
867 : Datum
868 228 : timestamptz_scale(PG_FUNCTION_ARGS)
869 : {
870 228 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
871 228 : int32 typmod = PG_GETARG_INT32(1);
872 : TimestampTz result;
873 :
874 228 : result = timestamp;
875 :
876 228 : AdjustTimestampForTypmod(&result, typmod, NULL);
877 :
878 228 : PG_RETURN_TIMESTAMPTZ(result);
879 : }
880 :
881 :
882 : /* interval_in()
883 : * Convert a string to internal form.
884 : *
885 : * External format(s):
886 : * Uses the generic date/time parsing and decoding routines.
887 : */
888 : Datum
889 32672 : interval_in(PG_FUNCTION_ARGS)
890 : {
891 32672 : char *str = PG_GETARG_CSTRING(0);
892 : #ifdef NOT_USED
893 : Oid typelem = PG_GETARG_OID(1);
894 : #endif
895 32672 : int32 typmod = PG_GETARG_INT32(2);
896 32672 : Node *escontext = fcinfo->context;
897 : Interval *result;
898 : struct pg_itm_in tt,
899 32672 : *itm_in = &tt;
900 : int dtype;
901 : int nf;
902 : int range;
903 : int dterr;
904 : char *field[MAXDATEFIELDS];
905 : int ftype[MAXDATEFIELDS];
906 : char workbuf[256];
907 : DateTimeErrorExtra extra;
908 :
909 32672 : itm_in->tm_year = 0;
910 32672 : itm_in->tm_mon = 0;
911 32672 : itm_in->tm_mday = 0;
912 32672 : itm_in->tm_usec = 0;
913 :
914 32672 : if (typmod >= 0)
915 168 : range = INTERVAL_RANGE(typmod);
916 : else
917 32504 : range = INTERVAL_FULL_RANGE;
918 :
919 32672 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
920 : ftype, MAXDATEFIELDS, &nf);
921 32672 : if (dterr == 0)
922 32672 : dterr = DecodeInterval(field, ftype, nf, range,
923 : &dtype, itm_in);
924 :
925 : /* if those functions think it's a bad format, try ISO8601 style */
926 32672 : if (dterr == DTERR_BAD_FORMAT)
927 306 : dterr = DecodeISO8601Interval(str,
928 : &dtype, itm_in);
929 :
930 32672 : if (dterr != 0)
931 : {
932 477 : if (dterr == DTERR_FIELD_OVERFLOW)
933 360 : dterr = DTERR_INTERVAL_OVERFLOW;
934 477 : DateTimeParseError(dterr, &extra, str, "interval", escontext);
935 12 : PG_RETURN_NULL();
936 : }
937 :
938 32195 : result = palloc_object(Interval);
939 :
940 32195 : switch (dtype)
941 : {
942 31709 : case DTK_DELTA:
943 31709 : if (itmin2interval(itm_in, result) != 0)
944 9 : ereturn(escontext, (Datum) 0,
945 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
946 : errmsg("interval out of range")));
947 31700 : break;
948 :
949 285 : case DTK_LATE:
950 285 : INTERVAL_NOEND(result);
951 285 : break;
952 :
953 201 : case DTK_EARLY:
954 201 : INTERVAL_NOBEGIN(result);
955 201 : break;
956 :
957 0 : default:
958 0 : elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
959 : dtype, str);
960 : }
961 :
962 32186 : AdjustIntervalForTypmod(result, typmod, escontext);
963 :
964 32180 : PG_RETURN_INTERVAL_P(result);
965 : }
966 :
967 : /* interval_out()
968 : * Convert a time span to external form.
969 : */
970 : Datum
971 8157 : interval_out(PG_FUNCTION_ARGS)
972 : {
973 8157 : Interval *span = PG_GETARG_INTERVAL_P(0);
974 : char *result;
975 : struct pg_itm tt,
976 8157 : *itm = &tt;
977 : char buf[MAXDATELEN + 1];
978 :
979 8157 : if (INTERVAL_NOT_FINITE(span))
980 1012 : EncodeSpecialInterval(span, buf);
981 : else
982 : {
983 7145 : interval2itm(*span, itm);
984 7145 : EncodeInterval(itm, IntervalStyle, buf);
985 : }
986 :
987 8157 : result = pstrdup(buf);
988 8157 : PG_RETURN_CSTRING(result);
989 : }
990 :
991 : /*
992 : * interval_recv - converts external binary format to interval
993 : */
994 : Datum
995 0 : interval_recv(PG_FUNCTION_ARGS)
996 : {
997 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
998 :
999 : #ifdef NOT_USED
1000 : Oid typelem = PG_GETARG_OID(1);
1001 : #endif
1002 0 : int32 typmod = PG_GETARG_INT32(2);
1003 : Interval *interval;
1004 :
1005 0 : interval = palloc_object(Interval);
1006 :
1007 0 : interval->time = pq_getmsgint64(buf);
1008 0 : interval->day = pq_getmsgint(buf, sizeof(interval->day));
1009 0 : interval->month = pq_getmsgint(buf, sizeof(interval->month));
1010 :
1011 0 : AdjustIntervalForTypmod(interval, typmod, NULL);
1012 :
1013 0 : PG_RETURN_INTERVAL_P(interval);
1014 : }
1015 :
1016 : /*
1017 : * interval_send - converts interval to binary format
1018 : */
1019 : Datum
1020 0 : interval_send(PG_FUNCTION_ARGS)
1021 : {
1022 0 : Interval *interval = PG_GETARG_INTERVAL_P(0);
1023 : StringInfoData buf;
1024 :
1025 0 : pq_begintypsend(&buf);
1026 0 : pq_sendint64(&buf, interval->time);
1027 0 : pq_sendint32(&buf, interval->day);
1028 0 : pq_sendint32(&buf, interval->month);
1029 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1030 : }
1031 :
1032 : /*
1033 : * The interval typmod stores a "range" in its high 16 bits and a "precision"
1034 : * in its low 16 bits. Both contribute to defining the resolution of the
1035 : * type. Range addresses resolution granules larger than one second, and
1036 : * precision specifies resolution below one second. This representation can
1037 : * express all SQL standard resolutions, but we implement them all in terms of
1038 : * truncating rightward from some position. Range is a bitmap of permitted
1039 : * fields, but only the temporally-smallest such field is significant to our
1040 : * calculations. Precision is a count of sub-second decimal places to retain.
1041 : * Setting all bits (INTERVAL_FULL_PRECISION) gives the same truncation
1042 : * semantics as choosing MAX_INTERVAL_PRECISION.
1043 : */
1044 : Datum
1045 177 : intervaltypmodin(PG_FUNCTION_ARGS)
1046 : {
1047 177 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1048 : int32 *tl;
1049 : int n;
1050 : int32 typmod;
1051 :
1052 177 : tl = ArrayGetIntegerTypmods(ta, &n);
1053 :
1054 : /*
1055 : * tl[0] - interval range (fields bitmask) tl[1] - precision (optional)
1056 : *
1057 : * Note we must validate tl[0] even though it's normally guaranteed
1058 : * correct by the grammar --- consider SELECT 'foo'::"interval"(1000).
1059 : */
1060 177 : if (n > 0)
1061 : {
1062 177 : switch (tl[0])
1063 : {
1064 177 : case INTERVAL_MASK(YEAR):
1065 : case INTERVAL_MASK(MONTH):
1066 : case INTERVAL_MASK(DAY):
1067 : case INTERVAL_MASK(HOUR):
1068 : case INTERVAL_MASK(MINUTE):
1069 : case INTERVAL_MASK(SECOND):
1070 : case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
1071 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
1072 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1073 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1074 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1075 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1076 : case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1077 : case INTERVAL_FULL_RANGE:
1078 : /* all OK */
1079 177 : break;
1080 0 : default:
1081 0 : ereport(ERROR,
1082 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1083 : errmsg("invalid INTERVAL type modifier")));
1084 : }
1085 : }
1086 :
1087 177 : if (n == 1)
1088 : {
1089 129 : if (tl[0] != INTERVAL_FULL_RANGE)
1090 129 : typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
1091 : else
1092 0 : typmod = -1;
1093 : }
1094 48 : else if (n == 2)
1095 : {
1096 48 : if (tl[1] < 0)
1097 0 : ereport(ERROR,
1098 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1099 : errmsg("INTERVAL(%d) precision must not be negative",
1100 : tl[1])));
1101 48 : if (tl[1] > MAX_INTERVAL_PRECISION)
1102 : {
1103 0 : ereport(WARNING,
1104 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1105 : errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
1106 : tl[1], MAX_INTERVAL_PRECISION)));
1107 0 : typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
1108 : }
1109 : else
1110 48 : typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
1111 : }
1112 : else
1113 : {
1114 0 : ereport(ERROR,
1115 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1116 : errmsg("invalid INTERVAL type modifier")));
1117 : typmod = 0; /* keep compiler quiet */
1118 : }
1119 :
1120 177 : PG_RETURN_INT32(typmod);
1121 : }
1122 :
1123 : Datum
1124 0 : intervaltypmodout(PG_FUNCTION_ARGS)
1125 : {
1126 0 : int32 typmod = PG_GETARG_INT32(0);
1127 0 : char *res = (char *) palloc(64);
1128 : int fields;
1129 : int precision;
1130 : const char *fieldstr;
1131 :
1132 0 : if (typmod < 0)
1133 : {
1134 0 : *res = '\0';
1135 0 : PG_RETURN_CSTRING(res);
1136 : }
1137 :
1138 0 : fields = INTERVAL_RANGE(typmod);
1139 0 : precision = INTERVAL_PRECISION(typmod);
1140 :
1141 0 : switch (fields)
1142 : {
1143 0 : case INTERVAL_MASK(YEAR):
1144 0 : fieldstr = " year";
1145 0 : break;
1146 0 : case INTERVAL_MASK(MONTH):
1147 0 : fieldstr = " month";
1148 0 : break;
1149 0 : case INTERVAL_MASK(DAY):
1150 0 : fieldstr = " day";
1151 0 : break;
1152 0 : case INTERVAL_MASK(HOUR):
1153 0 : fieldstr = " hour";
1154 0 : break;
1155 0 : case INTERVAL_MASK(MINUTE):
1156 0 : fieldstr = " minute";
1157 0 : break;
1158 0 : case INTERVAL_MASK(SECOND):
1159 0 : fieldstr = " second";
1160 0 : break;
1161 0 : case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
1162 0 : fieldstr = " year to month";
1163 0 : break;
1164 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
1165 0 : fieldstr = " day to hour";
1166 0 : break;
1167 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1168 0 : fieldstr = " day to minute";
1169 0 : break;
1170 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1171 0 : fieldstr = " day to second";
1172 0 : break;
1173 0 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1174 0 : fieldstr = " hour to minute";
1175 0 : break;
1176 0 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1177 0 : fieldstr = " hour to second";
1178 0 : break;
1179 0 : case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1180 0 : fieldstr = " minute to second";
1181 0 : break;
1182 0 : case INTERVAL_FULL_RANGE:
1183 0 : fieldstr = "";
1184 0 : break;
1185 0 : default:
1186 0 : elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
1187 : fieldstr = "";
1188 : break;
1189 : }
1190 :
1191 0 : if (precision != INTERVAL_FULL_PRECISION)
1192 0 : snprintf(res, 64, "%s(%d)", fieldstr, precision);
1193 : else
1194 0 : snprintf(res, 64, "%s", fieldstr);
1195 :
1196 0 : PG_RETURN_CSTRING(res);
1197 : }
1198 :
1199 : /*
1200 : * Given an interval typmod value, return a code for the least-significant
1201 : * field that the typmod allows to be nonzero, for instance given
1202 : * INTERVAL DAY TO HOUR we want to identify "hour".
1203 : *
1204 : * The results should be ordered by field significance, which means
1205 : * we can't use the dt.h macros YEAR etc, because for some odd reason
1206 : * they aren't ordered that way. Instead, arbitrarily represent
1207 : * SECOND = 0, MINUTE = 1, HOUR = 2, DAY = 3, MONTH = 4, YEAR = 5.
1208 : */
1209 : static int
1210 18 : intervaltypmodleastfield(int32 typmod)
1211 : {
1212 18 : if (typmod < 0)
1213 6 : return 0; /* SECOND */
1214 :
1215 12 : switch (INTERVAL_RANGE(typmod))
1216 : {
1217 3 : case INTERVAL_MASK(YEAR):
1218 3 : return 5; /* YEAR */
1219 6 : case INTERVAL_MASK(MONTH):
1220 6 : return 4; /* MONTH */
1221 0 : case INTERVAL_MASK(DAY):
1222 0 : return 3; /* DAY */
1223 0 : case INTERVAL_MASK(HOUR):
1224 0 : return 2; /* HOUR */
1225 0 : case INTERVAL_MASK(MINUTE):
1226 0 : return 1; /* MINUTE */
1227 0 : case INTERVAL_MASK(SECOND):
1228 0 : return 0; /* SECOND */
1229 0 : case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
1230 0 : return 4; /* MONTH */
1231 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
1232 0 : return 2; /* HOUR */
1233 3 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1234 3 : return 1; /* MINUTE */
1235 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1236 0 : return 0; /* SECOND */
1237 0 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1238 0 : return 1; /* MINUTE */
1239 0 : case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1240 0 : return 0; /* SECOND */
1241 0 : case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1242 0 : return 0; /* SECOND */
1243 0 : case INTERVAL_FULL_RANGE:
1244 0 : return 0; /* SECOND */
1245 0 : default:
1246 0 : elog(ERROR, "invalid INTERVAL typmod: 0x%x", typmod);
1247 : break;
1248 : }
1249 : return 0; /* can't get here, but keep compiler quiet */
1250 : }
1251 :
1252 :
1253 : /*
1254 : * interval_support()
1255 : *
1256 : * Planner support function for interval_scale().
1257 : *
1258 : * Flatten superfluous calls to interval_scale(). The interval typmod is
1259 : * complex to permit accepting and regurgitating all SQL standard variations.
1260 : * For truncation purposes, it boils down to a single, simple granularity.
1261 : */
1262 : Datum
1263 18 : interval_support(PG_FUNCTION_ARGS)
1264 : {
1265 18 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1266 18 : Node *ret = NULL;
1267 :
1268 18 : if (IsA(rawreq, SupportRequestSimplify))
1269 : {
1270 9 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1271 9 : FuncExpr *expr = req->fcall;
1272 : Node *typmod;
1273 :
1274 : Assert(list_length(expr->args) >= 2);
1275 :
1276 9 : typmod = (Node *) lsecond(expr->args);
1277 :
1278 9 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
1279 : {
1280 9 : Node *source = (Node *) linitial(expr->args);
1281 9 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
1282 : bool noop;
1283 :
1284 9 : if (new_typmod < 0)
1285 0 : noop = true;
1286 : else
1287 : {
1288 9 : int32 old_typmod = exprTypmod(source);
1289 : int old_least_field;
1290 : int new_least_field;
1291 : int old_precis;
1292 : int new_precis;
1293 :
1294 9 : old_least_field = intervaltypmodleastfield(old_typmod);
1295 9 : new_least_field = intervaltypmodleastfield(new_typmod);
1296 9 : if (old_typmod < 0)
1297 6 : old_precis = INTERVAL_FULL_PRECISION;
1298 : else
1299 3 : old_precis = INTERVAL_PRECISION(old_typmod);
1300 9 : new_precis = INTERVAL_PRECISION(new_typmod);
1301 :
1302 : /*
1303 : * Cast is a no-op if least field stays the same or decreases
1304 : * while precision stays the same or increases. But
1305 : * precision, which is to say, sub-second precision, only
1306 : * affects ranges that include SECOND.
1307 : */
1308 9 : noop = (new_least_field <= old_least_field) &&
1309 0 : (old_least_field > 0 /* SECOND */ ||
1310 0 : new_precis >= MAX_INTERVAL_PRECISION ||
1311 : new_precis >= old_precis);
1312 : }
1313 9 : if (noop)
1314 0 : ret = relabel_to_typmod(source, new_typmod);
1315 : }
1316 : }
1317 :
1318 18 : PG_RETURN_POINTER(ret);
1319 : }
1320 :
1321 : /* interval_scale()
1322 : * Adjust interval type for specified fields.
1323 : * Used by PostgreSQL type system to stuff columns.
1324 : */
1325 : Datum
1326 108 : interval_scale(PG_FUNCTION_ARGS)
1327 : {
1328 108 : Interval *interval = PG_GETARG_INTERVAL_P(0);
1329 108 : int32 typmod = PG_GETARG_INT32(1);
1330 : Interval *result;
1331 :
1332 108 : result = palloc_object(Interval);
1333 108 : *result = *interval;
1334 :
1335 108 : AdjustIntervalForTypmod(result, typmod, NULL);
1336 :
1337 108 : PG_RETURN_INTERVAL_P(result);
1338 : }
1339 :
1340 : /*
1341 : * Adjust interval for specified precision, in both YEAR to SECOND
1342 : * range and sub-second precision.
1343 : *
1344 : * Returns true on success, false on failure (if escontext points to an
1345 : * ErrorSaveContext; otherwise errors are thrown).
1346 : */
1347 : static bool
1348 32294 : AdjustIntervalForTypmod(Interval *interval, int32 typmod,
1349 : Node *escontext)
1350 : {
1351 : static const int64 IntervalScales[MAX_INTERVAL_PRECISION + 1] = {
1352 : INT64CONST(1000000),
1353 : INT64CONST(100000),
1354 : INT64CONST(10000),
1355 : INT64CONST(1000),
1356 : INT64CONST(100),
1357 : INT64CONST(10),
1358 : INT64CONST(1)
1359 : };
1360 :
1361 : static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION + 1] = {
1362 : INT64CONST(500000),
1363 : INT64CONST(50000),
1364 : INT64CONST(5000),
1365 : INT64CONST(500),
1366 : INT64CONST(50),
1367 : INT64CONST(5),
1368 : INT64CONST(0)
1369 : };
1370 :
1371 : /* Typmod has no effect on infinite intervals */
1372 32294 : if (INTERVAL_NOT_FINITE(interval))
1373 510 : return true;
1374 :
1375 : /*
1376 : * Unspecified range and precision? Then not necessary to adjust. Setting
1377 : * typmod to -1 is the convention for all data types.
1378 : */
1379 31784 : if (typmod >= 0)
1380 : {
1381 231 : int range = INTERVAL_RANGE(typmod);
1382 231 : int precision = INTERVAL_PRECISION(typmod);
1383 :
1384 : /*
1385 : * Our interpretation of intervals with a limited set of fields is
1386 : * that fields to the right of the last one specified are zeroed out,
1387 : * but those to the left of it remain valid. Thus for example there
1388 : * is no operational difference between INTERVAL YEAR TO MONTH and
1389 : * INTERVAL MONTH. In some cases we could meaningfully enforce that
1390 : * higher-order fields are zero; for example INTERVAL DAY could reject
1391 : * nonzero "month" field. However that seems a bit pointless when we
1392 : * can't do it consistently. (We cannot enforce a range limit on the
1393 : * highest expected field, since we do not have any equivalent of
1394 : * SQL's <interval leading field precision>.) If we ever decide to
1395 : * revisit this, interval_support will likely require adjusting.
1396 : *
1397 : * Note: before PG 8.4 we interpreted a limited set of fields as
1398 : * actually causing a "modulo" operation on a given value, potentially
1399 : * losing high-order as well as low-order information. But there is
1400 : * no support for such behavior in the standard, and it seems fairly
1401 : * undesirable on data consistency grounds anyway. Now we only
1402 : * perform truncation or rounding of low-order fields.
1403 : */
1404 231 : if (range == INTERVAL_FULL_RANGE)
1405 : {
1406 : /* Do nothing... */
1407 : }
1408 225 : else if (range == INTERVAL_MASK(YEAR))
1409 : {
1410 33 : interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
1411 33 : interval->day = 0;
1412 33 : interval->time = 0;
1413 : }
1414 192 : else if (range == INTERVAL_MASK(MONTH))
1415 : {
1416 36 : interval->day = 0;
1417 36 : interval->time = 0;
1418 : }
1419 : /* YEAR TO MONTH */
1420 156 : else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
1421 : {
1422 9 : interval->day = 0;
1423 9 : interval->time = 0;
1424 : }
1425 147 : else if (range == INTERVAL_MASK(DAY))
1426 : {
1427 6 : interval->time = 0;
1428 : }
1429 141 : else if (range == INTERVAL_MASK(HOUR))
1430 : {
1431 6 : interval->time = (interval->time / USECS_PER_HOUR) *
1432 : USECS_PER_HOUR;
1433 : }
1434 135 : else if (range == INTERVAL_MASK(MINUTE))
1435 : {
1436 6 : interval->time = (interval->time / USECS_PER_MINUTE) *
1437 : USECS_PER_MINUTE;
1438 : }
1439 129 : else if (range == INTERVAL_MASK(SECOND))
1440 : {
1441 : /* fractional-second rounding will be dealt with below */
1442 : }
1443 : /* DAY TO HOUR */
1444 111 : else if (range == (INTERVAL_MASK(DAY) |
1445 : INTERVAL_MASK(HOUR)))
1446 : {
1447 12 : interval->time = (interval->time / USECS_PER_HOUR) *
1448 : USECS_PER_HOUR;
1449 : }
1450 : /* DAY TO MINUTE */
1451 99 : else if (range == (INTERVAL_MASK(DAY) |
1452 : INTERVAL_MASK(HOUR) |
1453 : INTERVAL_MASK(MINUTE)))
1454 : {
1455 36 : interval->time = (interval->time / USECS_PER_MINUTE) *
1456 : USECS_PER_MINUTE;
1457 : }
1458 : /* DAY TO SECOND */
1459 63 : else if (range == (INTERVAL_MASK(DAY) |
1460 : INTERVAL_MASK(HOUR) |
1461 : INTERVAL_MASK(MINUTE) |
1462 : INTERVAL_MASK(SECOND)))
1463 : {
1464 : /* fractional-second rounding will be dealt with below */
1465 : }
1466 : /* HOUR TO MINUTE */
1467 45 : else if (range == (INTERVAL_MASK(HOUR) |
1468 : INTERVAL_MASK(MINUTE)))
1469 : {
1470 6 : interval->time = (interval->time / USECS_PER_MINUTE) *
1471 : USECS_PER_MINUTE;
1472 : }
1473 : /* HOUR TO SECOND */
1474 39 : else if (range == (INTERVAL_MASK(HOUR) |
1475 : INTERVAL_MASK(MINUTE) |
1476 : INTERVAL_MASK(SECOND)))
1477 : {
1478 : /* fractional-second rounding will be dealt with below */
1479 : }
1480 : /* MINUTE TO SECOND */
1481 27 : else if (range == (INTERVAL_MASK(MINUTE) |
1482 : INTERVAL_MASK(SECOND)))
1483 : {
1484 : /* fractional-second rounding will be dealt with below */
1485 : }
1486 : else
1487 0 : elog(ERROR, "unrecognized interval typmod: %d", typmod);
1488 :
1489 : /* Need to adjust sub-second precision? */
1490 231 : if (precision != INTERVAL_FULL_PRECISION)
1491 : {
1492 39 : if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
1493 0 : ereturn(escontext, false,
1494 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1495 : errmsg("interval(%d) precision must be between %d and %d",
1496 : precision, 0, MAX_INTERVAL_PRECISION)));
1497 :
1498 39 : if (interval->time >= INT64CONST(0))
1499 : {
1500 36 : if (pg_add_s64_overflow(interval->time,
1501 36 : IntervalOffsets[precision],
1502 36 : &interval->time))
1503 3 : ereturn(escontext, false,
1504 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1505 : errmsg("interval out of range")));
1506 33 : interval->time -= interval->time % IntervalScales[precision];
1507 : }
1508 : else
1509 : {
1510 3 : if (pg_sub_s64_overflow(interval->time,
1511 3 : IntervalOffsets[precision],
1512 3 : &interval->time))
1513 3 : ereturn(escontext, false,
1514 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1515 : errmsg("interval out of range")));
1516 0 : interval->time -= interval->time % IntervalScales[precision];
1517 : }
1518 : }
1519 : }
1520 :
1521 31778 : return true;
1522 : }
1523 :
1524 : /*
1525 : * make_interval - numeric Interval constructor
1526 : */
1527 : Datum
1528 66 : make_interval(PG_FUNCTION_ARGS)
1529 : {
1530 66 : int32 years = PG_GETARG_INT32(0);
1531 66 : int32 months = PG_GETARG_INT32(1);
1532 66 : int32 weeks = PG_GETARG_INT32(2);
1533 66 : int32 days = PG_GETARG_INT32(3);
1534 66 : int32 hours = PG_GETARG_INT32(4);
1535 66 : int32 mins = PG_GETARG_INT32(5);
1536 66 : double secs = PG_GETARG_FLOAT8(6);
1537 : Interval *result;
1538 :
1539 : /*
1540 : * Reject out-of-range inputs. We reject any input values that cause
1541 : * integer overflow of the corresponding interval fields.
1542 : */
1543 66 : if (isinf(secs) || isnan(secs))
1544 6 : goto out_of_range;
1545 :
1546 60 : result = palloc_object(Interval);
1547 :
1548 : /* years and months -> months */
1549 114 : if (pg_mul_s32_overflow(years, MONTHS_PER_YEAR, &result->month) ||
1550 54 : pg_add_s32_overflow(result->month, months, &result->month))
1551 12 : goto out_of_range;
1552 :
1553 : /* weeks and days -> days */
1554 90 : if (pg_mul_s32_overflow(weeks, DAYS_PER_WEEK, &result->day) ||
1555 42 : pg_add_s32_overflow(result->day, days, &result->day))
1556 12 : goto out_of_range;
1557 :
1558 : /* hours and mins -> usecs (cannot overflow 64-bit) */
1559 36 : result->time = hours * USECS_PER_HOUR + mins * USECS_PER_MINUTE;
1560 :
1561 : /* secs -> usecs */
1562 36 : secs = rint(float8_mul(secs, USECS_PER_SEC));
1563 60 : if (!FLOAT8_FITS_IN_INT64(secs) ||
1564 27 : pg_add_s64_overflow(result->time, (int64) secs, &result->time))
1565 12 : goto out_of_range;
1566 :
1567 : /* make sure that the result is finite */
1568 21 : if (INTERVAL_NOT_FINITE(result))
1569 0 : goto out_of_range;
1570 :
1571 21 : PG_RETURN_INTERVAL_P(result);
1572 :
1573 42 : out_of_range:
1574 42 : ereport(ERROR,
1575 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1576 : errmsg("interval out of range"));
1577 :
1578 : PG_RETURN_NULL(); /* keep compiler quiet */
1579 : }
1580 :
1581 : /* EncodeSpecialTimestamp()
1582 : * Convert reserved timestamp data type to string.
1583 : */
1584 : void
1585 663 : EncodeSpecialTimestamp(Timestamp dt, char *str)
1586 : {
1587 663 : if (TIMESTAMP_IS_NOBEGIN(dt))
1588 323 : strcpy(str, EARLY);
1589 340 : else if (TIMESTAMP_IS_NOEND(dt))
1590 340 : strcpy(str, LATE);
1591 : else /* shouldn't happen */
1592 0 : elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
1593 663 : }
1594 :
1595 : static void
1596 1012 : EncodeSpecialInterval(const Interval *interval, char *str)
1597 : {
1598 1012 : if (INTERVAL_IS_NOBEGIN(interval))
1599 497 : strcpy(str, EARLY);
1600 515 : else if (INTERVAL_IS_NOEND(interval))
1601 515 : strcpy(str, LATE);
1602 : else /* shouldn't happen */
1603 0 : elog(ERROR, "invalid argument for EncodeSpecialInterval");
1604 1012 : }
1605 :
1606 : Datum
1607 35329 : now(PG_FUNCTION_ARGS)
1608 : {
1609 35329 : PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
1610 : }
1611 :
1612 : Datum
1613 3 : statement_timestamp(PG_FUNCTION_ARGS)
1614 : {
1615 3 : PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
1616 : }
1617 :
1618 : Datum
1619 14 : clock_timestamp(PG_FUNCTION_ARGS)
1620 : {
1621 14 : PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
1622 : }
1623 :
1624 : Datum
1625 0 : pg_postmaster_start_time(PG_FUNCTION_ARGS)
1626 : {
1627 0 : PG_RETURN_TIMESTAMPTZ(PgStartTime);
1628 : }
1629 :
1630 : Datum
1631 0 : pg_conf_load_time(PG_FUNCTION_ARGS)
1632 : {
1633 0 : PG_RETURN_TIMESTAMPTZ(PgReloadTime);
1634 : }
1635 :
1636 : /*
1637 : * GetCurrentTimestamp -- get the current operating system time
1638 : *
1639 : * Result is in the form of a TimestampTz value, and is expressed to the
1640 : * full precision of the gettimeofday() syscall
1641 : */
1642 : TimestampTz
1643 4933481 : GetCurrentTimestamp(void)
1644 : {
1645 : TimestampTz result;
1646 : struct timeval tp;
1647 :
1648 4933481 : gettimeofday(&tp, NULL);
1649 :
1650 4933481 : result = (TimestampTz) tp.tv_sec -
1651 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1652 4933481 : result = (result * USECS_PER_SEC) + tp.tv_usec;
1653 :
1654 4933481 : return result;
1655 : }
1656 :
1657 : /*
1658 : * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
1659 : */
1660 : TimestampTz
1661 174 : GetSQLCurrentTimestamp(int32 typmod)
1662 : {
1663 : TimestampTz ts;
1664 :
1665 174 : ts = GetCurrentTransactionStartTimestamp();
1666 174 : if (typmod >= 0)
1667 36 : AdjustTimestampForTypmod(&ts, typmod, NULL);
1668 174 : return ts;
1669 : }
1670 :
1671 : /*
1672 : * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
1673 : */
1674 : Timestamp
1675 33 : GetSQLLocalTimestamp(int32 typmod)
1676 : {
1677 : Timestamp ts;
1678 :
1679 33 : ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
1680 33 : if (typmod >= 0)
1681 3 : AdjustTimestampForTypmod(&ts, typmod, NULL);
1682 33 : return ts;
1683 : }
1684 :
1685 : /*
1686 : * timeofday(*) -- returns the current time as a text.
1687 : */
1688 : Datum
1689 800 : timeofday(PG_FUNCTION_ARGS)
1690 : {
1691 : struct timeval tp;
1692 : char templ[128];
1693 : char buf[128];
1694 : pg_time_t tt;
1695 :
1696 800 : gettimeofday(&tp, NULL);
1697 800 : tt = (pg_time_t) tp.tv_sec;
1698 800 : pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1699 800 : pg_localtime(&tt, session_timezone));
1700 800 : snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1701 :
1702 800 : PG_RETURN_TEXT_P(cstring_to_text(buf));
1703 : }
1704 :
1705 : /*
1706 : * TimestampDifference -- convert the difference between two timestamps
1707 : * into integer seconds and microseconds
1708 : *
1709 : * This is typically used to calculate a wait timeout for select(2),
1710 : * which explains the otherwise-odd choice of output format.
1711 : *
1712 : * Both inputs must be ordinary finite timestamps (in current usage,
1713 : * they'll be results from GetCurrentTimestamp()).
1714 : *
1715 : * We expect start_time <= stop_time. If not, we return zeros,
1716 : * since then we're already past the previously determined stop_time.
1717 : */
1718 : void
1719 667452 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
1720 : long *secs, int *microsecs)
1721 : {
1722 667452 : TimestampTz diff = stop_time - start_time;
1723 :
1724 667452 : if (diff <= 0)
1725 : {
1726 151 : *secs = 0;
1727 151 : *microsecs = 0;
1728 : }
1729 : else
1730 : {
1731 667301 : *secs = (long) (diff / USECS_PER_SEC);
1732 667301 : *microsecs = (int) (diff % USECS_PER_SEC);
1733 : }
1734 667452 : }
1735 :
1736 : /*
1737 : * TimestampDifferenceMilliseconds -- convert the difference between two
1738 : * timestamps into integer milliseconds
1739 : *
1740 : * This is typically used to calculate a wait timeout for WaitLatch()
1741 : * or a related function. The choice of "long" as the result type
1742 : * is to harmonize with that; furthermore, we clamp the result to at most
1743 : * INT_MAX milliseconds, because that's all that WaitLatch() allows.
1744 : *
1745 : * We expect start_time <= stop_time. If not, we return zero,
1746 : * since then we're already past the previously determined stop_time.
1747 : *
1748 : * Subtracting finite and infinite timestamps works correctly, returning
1749 : * zero or INT_MAX as appropriate.
1750 : *
1751 : * Note we round up any fractional millisecond, since waiting for just
1752 : * less than the intended timeout is undesirable.
1753 : */
1754 : long
1755 344092 : TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
1756 : {
1757 : TimestampTz diff;
1758 :
1759 : /* Deal with zero or negative elapsed time quickly. */
1760 344092 : if (start_time >= stop_time)
1761 44 : return 0;
1762 : /* To not fail with timestamp infinities, we must detect overflow. */
1763 344048 : if (pg_sub_s64_overflow(stop_time, start_time, &diff))
1764 0 : return (long) INT_MAX;
1765 344048 : if (diff >= (INT_MAX * INT64CONST(1000) - 999))
1766 0 : return (long) INT_MAX;
1767 : else
1768 344048 : return (long) ((diff + 999) / 1000);
1769 : }
1770 :
1771 : /*
1772 : * TimestampDifferenceExceeds -- report whether the difference between two
1773 : * timestamps is >= a threshold (expressed in milliseconds)
1774 : *
1775 : * Both inputs must be ordinary finite timestamps (in current usage,
1776 : * they'll be results from GetCurrentTimestamp()).
1777 : */
1778 : bool
1779 675296 : TimestampDifferenceExceeds(TimestampTz start_time,
1780 : TimestampTz stop_time,
1781 : int msec)
1782 : {
1783 675296 : TimestampTz diff = stop_time - start_time;
1784 :
1785 675296 : return (diff >= msec * INT64CONST(1000));
1786 : }
1787 :
1788 : /*
1789 : * Check if the difference between two timestamps is >= a given
1790 : * threshold (expressed in seconds).
1791 : */
1792 : bool
1793 0 : TimestampDifferenceExceedsSeconds(TimestampTz start_time,
1794 : TimestampTz stop_time,
1795 : int threshold_sec)
1796 : {
1797 : long secs;
1798 : int usecs;
1799 :
1800 : /* Calculate the difference in seconds */
1801 0 : TimestampDifference(start_time, stop_time, &secs, &usecs);
1802 :
1803 0 : return (secs >= threshold_sec);
1804 : }
1805 :
1806 : /*
1807 : * Convert a time_t to TimestampTz.
1808 : *
1809 : * We do not use time_t internally in Postgres, but this is provided for use
1810 : * by functions that need to interpret, say, a stat(2) result.
1811 : *
1812 : * To avoid having the function's ABI vary depending on the width of time_t,
1813 : * we declare the argument as pg_time_t, which is cast-compatible with
1814 : * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1815 : * This detail should be invisible to callers, at least at source code level.
1816 : */
1817 : TimestampTz
1818 21291 : time_t_to_timestamptz(pg_time_t tm)
1819 : {
1820 : TimestampTz result;
1821 :
1822 21291 : result = (TimestampTz) tm -
1823 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1824 21291 : result *= USECS_PER_SEC;
1825 :
1826 21291 : return result;
1827 : }
1828 :
1829 : /*
1830 : * Convert a TimestampTz to time_t.
1831 : *
1832 : * This too is just marginally useful, but some places need it.
1833 : *
1834 : * To avoid having the function's ABI vary depending on the width of time_t,
1835 : * we declare the result as pg_time_t, which is cast-compatible with
1836 : * time_t but always 64 bits wide (unless the platform has no 64-bit type).
1837 : * This detail should be invisible to callers, at least at source code level.
1838 : */
1839 : pg_time_t
1840 25420 : timestamptz_to_time_t(TimestampTz t)
1841 : {
1842 : pg_time_t result;
1843 :
1844 25420 : result = (pg_time_t) (t / USECS_PER_SEC +
1845 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
1846 :
1847 25420 : return result;
1848 : }
1849 :
1850 : /*
1851 : * Produce a C-string representation of a TimestampTz.
1852 : *
1853 : * This is mostly for use in emitting messages. The primary difference
1854 : * from timestamptz_out is that we force the output format to ISO. Note
1855 : * also that the result is in a static buffer, not pstrdup'd.
1856 : *
1857 : * See also pg_strftime.
1858 : */
1859 : const char *
1860 1689 : timestamptz_to_str(TimestampTz t)
1861 : {
1862 : static char buf[MAXDATELEN + 1];
1863 : int tz;
1864 : struct pg_tm tt,
1865 1689 : *tm = &tt;
1866 : fsec_t fsec;
1867 : const char *tzn;
1868 :
1869 1689 : if (TIMESTAMP_NOT_FINITE(t))
1870 0 : EncodeSpecialTimestamp(t, buf);
1871 1689 : else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
1872 1689 : EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1873 : else
1874 0 : strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1875 :
1876 1689 : return buf;
1877 : }
1878 :
1879 :
1880 : void
1881 156502 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
1882 : {
1883 : TimeOffset time;
1884 :
1885 156502 : time = jd;
1886 :
1887 156502 : *hour = time / USECS_PER_HOUR;
1888 156502 : time -= (*hour) * USECS_PER_HOUR;
1889 156502 : *min = time / USECS_PER_MINUTE;
1890 156502 : time -= (*min) * USECS_PER_MINUTE;
1891 156502 : *sec = time / USECS_PER_SEC;
1892 156502 : *fsec = time - (*sec * USECS_PER_SEC);
1893 156502 : } /* dt2time() */
1894 :
1895 :
1896 : /*
1897 : * timestamp2tm() - Convert timestamp data type to POSIX time structure.
1898 : *
1899 : * Note that year is _not_ 1900-based, but is an explicit full value.
1900 : * Also, month is one-based, _not_ zero-based.
1901 : * Returns:
1902 : * 0 on success
1903 : * -1 on out of range
1904 : *
1905 : * If attimezone is NULL, the global timezone setting will be used.
1906 : */
1907 : int
1908 156496 : timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
1909 : {
1910 : Timestamp date;
1911 : Timestamp time;
1912 : pg_time_t utime;
1913 :
1914 : /* Use session timezone if caller asks for default */
1915 156496 : if (attimezone == NULL)
1916 120075 : attimezone = session_timezone;
1917 :
1918 156496 : time = dt;
1919 156496 : TMODULO(time, date, USECS_PER_DAY);
1920 :
1921 156496 : if (time < INT64CONST(0))
1922 : {
1923 51123 : time += USECS_PER_DAY;
1924 51123 : date -= 1;
1925 : }
1926 :
1927 : /* add offset to go from J2000 back to standard Julian date */
1928 156496 : date += POSTGRES_EPOCH_JDATE;
1929 :
1930 : /* Julian day routine does not work for negative Julian days */
1931 156496 : if (date < 0 || date > (Timestamp) INT_MAX)
1932 0 : return -1;
1933 :
1934 156496 : j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1935 156496 : dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
1936 :
1937 : /* Done if no TZ conversion wanted */
1938 156496 : if (tzp == NULL)
1939 : {
1940 43052 : tm->tm_isdst = -1;
1941 43052 : tm->tm_gmtoff = 0;
1942 43052 : tm->tm_zone = NULL;
1943 43052 : if (tzn != NULL)
1944 0 : *tzn = NULL;
1945 43052 : return 0;
1946 : }
1947 :
1948 : /*
1949 : * If the time falls within the range of pg_time_t, use pg_localtime() to
1950 : * rotate to the local time zone.
1951 : *
1952 : * First, convert to an integral timestamp, avoiding possibly
1953 : * platform-specific roundoff-in-wrong-direction errors, and adjust to
1954 : * Unix epoch. Then see if we can convert to pg_time_t without loss. This
1955 : * coding avoids hardwiring any assumptions about the width of pg_time_t,
1956 : * so it should behave sanely on machines without int64.
1957 : */
1958 113444 : dt = (dt - *fsec) / USECS_PER_SEC +
1959 : (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1960 113444 : utime = (pg_time_t) dt;
1961 113444 : if ((Timestamp) utime == dt)
1962 : {
1963 113444 : struct pg_tm *tx = pg_localtime(&utime, attimezone);
1964 :
1965 113444 : tm->tm_year = tx->tm_year + 1900;
1966 113444 : tm->tm_mon = tx->tm_mon + 1;
1967 113444 : tm->tm_mday = tx->tm_mday;
1968 113444 : tm->tm_hour = tx->tm_hour;
1969 113444 : tm->tm_min = tx->tm_min;
1970 113444 : tm->tm_sec = tx->tm_sec;
1971 113444 : tm->tm_isdst = tx->tm_isdst;
1972 113444 : tm->tm_gmtoff = tx->tm_gmtoff;
1973 113444 : tm->tm_zone = tx->tm_zone;
1974 113444 : *tzp = -tm->tm_gmtoff;
1975 113444 : if (tzn != NULL)
1976 43882 : *tzn = tm->tm_zone;
1977 : }
1978 : else
1979 : {
1980 : /*
1981 : * When out of range of pg_time_t, treat as GMT
1982 : */
1983 0 : *tzp = 0;
1984 : /* Mark this as *no* time zone available */
1985 0 : tm->tm_isdst = -1;
1986 0 : tm->tm_gmtoff = 0;
1987 0 : tm->tm_zone = NULL;
1988 0 : if (tzn != NULL)
1989 0 : *tzn = NULL;
1990 : }
1991 :
1992 113444 : return 0;
1993 : }
1994 :
1995 :
1996 : /* tm2timestamp()
1997 : * Convert a tm structure to a timestamp data type.
1998 : * Note that year is _not_ 1900-based, but is an explicit full value.
1999 : * Also, month is one-based, _not_ zero-based.
2000 : *
2001 : * Returns -1 on failure (value out of range).
2002 : */
2003 : int
2004 110687 : tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
2005 : {
2006 : TimeOffset date;
2007 : TimeOffset time;
2008 :
2009 : /* Prevent overflow in Julian-day routines */
2010 110687 : if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
2011 : {
2012 6 : *result = 0; /* keep compiler quiet */
2013 6 : return -1;
2014 : }
2015 :
2016 110681 : date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
2017 110681 : time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
2018 :
2019 110681 : if (unlikely(pg_mul_s64_overflow(date, USECS_PER_DAY, result) ||
2020 : pg_add_s64_overflow(*result, time, result)))
2021 : {
2022 3 : *result = 0; /* keep compiler quiet */
2023 3 : return -1;
2024 : }
2025 110678 : if (tzp != NULL)
2026 52317 : *result = dt2local(*result, -(*tzp));
2027 :
2028 : /* final range check catches just-out-of-range timestamps */
2029 110678 : if (!IS_VALID_TIMESTAMP(*result))
2030 : {
2031 14 : *result = 0; /* keep compiler quiet */
2032 14 : return -1;
2033 : }
2034 :
2035 110664 : return 0;
2036 : }
2037 :
2038 :
2039 : /* interval2itm()
2040 : * Convert an Interval to a pg_itm structure.
2041 : * Note: overflow is not possible, because the pg_itm fields are
2042 : * wide enough for all possible conversion results.
2043 : */
2044 : void
2045 8205 : interval2itm(Interval span, struct pg_itm *itm)
2046 : {
2047 : TimeOffset time;
2048 : TimeOffset tfrac;
2049 :
2050 8205 : itm->tm_year = span.month / MONTHS_PER_YEAR;
2051 8205 : itm->tm_mon = span.month % MONTHS_PER_YEAR;
2052 8205 : itm->tm_mday = span.day;
2053 8205 : time = span.time;
2054 :
2055 8205 : tfrac = time / USECS_PER_HOUR;
2056 8205 : time -= tfrac * USECS_PER_HOUR;
2057 8205 : itm->tm_hour = tfrac;
2058 8205 : tfrac = time / USECS_PER_MINUTE;
2059 8205 : time -= tfrac * USECS_PER_MINUTE;
2060 8205 : itm->tm_min = (int) tfrac;
2061 8205 : tfrac = time / USECS_PER_SEC;
2062 8205 : time -= tfrac * USECS_PER_SEC;
2063 8205 : itm->tm_sec = (int) tfrac;
2064 8205 : itm->tm_usec = (int) time;
2065 8205 : }
2066 :
2067 : /* itm2interval()
2068 : * Convert a pg_itm structure to an Interval.
2069 : * Returns 0 if OK, -1 on overflow.
2070 : *
2071 : * This is for use in computations expected to produce finite results. Any
2072 : * inputs that lead to infinite results are treated as overflows.
2073 : */
2074 : int
2075 0 : itm2interval(struct pg_itm *itm, Interval *span)
2076 : {
2077 0 : int64 total_months = (int64) itm->tm_year * MONTHS_PER_YEAR + itm->tm_mon;
2078 :
2079 0 : if (total_months > INT_MAX || total_months < INT_MIN)
2080 0 : return -1;
2081 0 : span->month = (int32) total_months;
2082 0 : span->day = itm->tm_mday;
2083 0 : if (pg_mul_s64_overflow(itm->tm_hour, USECS_PER_HOUR,
2084 0 : &span->time))
2085 0 : return -1;
2086 : /* tm_min, tm_sec are 32 bits, so intermediate products can't overflow */
2087 0 : if (pg_add_s64_overflow(span->time, itm->tm_min * USECS_PER_MINUTE,
2088 0 : &span->time))
2089 0 : return -1;
2090 0 : if (pg_add_s64_overflow(span->time, itm->tm_sec * USECS_PER_SEC,
2091 0 : &span->time))
2092 0 : return -1;
2093 0 : if (pg_add_s64_overflow(span->time, itm->tm_usec,
2094 0 : &span->time))
2095 0 : return -1;
2096 0 : if (INTERVAL_NOT_FINITE(span))
2097 0 : return -1;
2098 0 : return 0;
2099 : }
2100 :
2101 : /* itmin2interval()
2102 : * Convert a pg_itm_in structure to an Interval.
2103 : * Returns 0 if OK, -1 on overflow.
2104 : *
2105 : * Note: if the result is infinite, it is not treated as an overflow. This
2106 : * avoids any dump/reload hazards from pre-17 databases that do not support
2107 : * infinite intervals, but do allow finite intervals with all fields set to
2108 : * INT_MIN/INT_MAX (outside the documented range). Such intervals will be
2109 : * silently converted to +/-infinity. This may not be ideal, but seems
2110 : * preferable to failure, and ought to be pretty unlikely in practice.
2111 : */
2112 : int
2113 38944 : itmin2interval(struct pg_itm_in *itm_in, Interval *span)
2114 : {
2115 38944 : int64 total_months = (int64) itm_in->tm_year * MONTHS_PER_YEAR + itm_in->tm_mon;
2116 :
2117 38944 : if (total_months > INT_MAX || total_months < INT_MIN)
2118 9 : return -1;
2119 38935 : span->month = (int32) total_months;
2120 38935 : span->day = itm_in->tm_mday;
2121 38935 : span->time = itm_in->tm_usec;
2122 38935 : return 0;
2123 : }
2124 :
2125 : static TimeOffset
2126 110681 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
2127 : {
2128 110681 : return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
2129 : }
2130 :
2131 : static Timestamp
2132 60649 : dt2local(Timestamp dt, int timezone)
2133 : {
2134 60649 : dt -= (timezone * USECS_PER_SEC);
2135 60649 : return dt;
2136 : }
2137 :
2138 :
2139 : /*****************************************************************************
2140 : * PUBLIC ROUTINES *
2141 : *****************************************************************************/
2142 :
2143 :
2144 : Datum
2145 0 : timestamp_finite(PG_FUNCTION_ARGS)
2146 : {
2147 0 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
2148 :
2149 0 : PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
2150 : }
2151 :
2152 : Datum
2153 159 : interval_finite(PG_FUNCTION_ARGS)
2154 : {
2155 159 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2156 :
2157 159 : PG_RETURN_BOOL(!INTERVAL_NOT_FINITE(interval));
2158 : }
2159 :
2160 :
2161 : /*----------------------------------------------------------
2162 : * Relational operators for timestamp.
2163 : *---------------------------------------------------------*/
2164 :
2165 : void
2166 14188 : GetEpochTime(struct pg_tm *tm)
2167 : {
2168 : struct pg_tm *t0;
2169 14188 : pg_time_t epoch = 0;
2170 :
2171 14188 : t0 = pg_gmtime(&epoch);
2172 :
2173 14188 : if (t0 == NULL)
2174 0 : elog(ERROR, "could not convert epoch to timestamp: %m");
2175 :
2176 14188 : tm->tm_year = t0->tm_year;
2177 14188 : tm->tm_mon = t0->tm_mon;
2178 14188 : tm->tm_mday = t0->tm_mday;
2179 14188 : tm->tm_hour = t0->tm_hour;
2180 14188 : tm->tm_min = t0->tm_min;
2181 14188 : tm->tm_sec = t0->tm_sec;
2182 :
2183 14188 : tm->tm_year += 1900;
2184 14188 : tm->tm_mon++;
2185 14188 : }
2186 :
2187 : Timestamp
2188 14185 : SetEpochTimestamp(void)
2189 : {
2190 : Timestamp dt;
2191 : struct pg_tm tt,
2192 14185 : *tm = &tt;
2193 :
2194 14185 : GetEpochTime(tm);
2195 : /* we don't bother to test for failure ... */
2196 14185 : tm2timestamp(tm, 0, NULL, &dt);
2197 :
2198 14185 : return dt;
2199 : } /* SetEpochTimestamp() */
2200 :
2201 : /*
2202 : * We are currently sharing some code between timestamp and timestamptz.
2203 : * The comparison functions are among them. - thomas 2001-09-25
2204 : *
2205 : * timestamp_relop - is timestamp1 relop timestamp2
2206 : */
2207 : int
2208 233812 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
2209 : {
2210 233812 : return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2211 : }
2212 :
2213 : Datum
2214 14379 : timestamp_eq(PG_FUNCTION_ARGS)
2215 : {
2216 14379 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2217 14379 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2218 :
2219 14379 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
2220 : }
2221 :
2222 : Datum
2223 393 : timestamp_ne(PG_FUNCTION_ARGS)
2224 : {
2225 393 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2226 393 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2227 :
2228 393 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2229 : }
2230 :
2231 : Datum
2232 88962 : timestamp_lt(PG_FUNCTION_ARGS)
2233 : {
2234 88962 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2235 88962 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2236 :
2237 88962 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2238 : }
2239 :
2240 : Datum
2241 49716 : timestamp_gt(PG_FUNCTION_ARGS)
2242 : {
2243 49716 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2244 49716 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2245 :
2246 49716 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2247 : }
2248 :
2249 : Datum
2250 9466 : timestamp_le(PG_FUNCTION_ARGS)
2251 : {
2252 9466 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2253 9466 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2254 :
2255 9466 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2256 : }
2257 :
2258 : Datum
2259 9776 : timestamp_ge(PG_FUNCTION_ARGS)
2260 : {
2261 9776 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2262 9776 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2263 :
2264 9776 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2265 : }
2266 :
2267 : Datum
2268 20907 : timestamp_cmp(PG_FUNCTION_ARGS)
2269 : {
2270 20907 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2271 20907 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2272 :
2273 20907 : PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
2274 : }
2275 :
2276 : Datum
2277 287 : timestamp_sortsupport(PG_FUNCTION_ARGS)
2278 : {
2279 287 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
2280 :
2281 287 : ssup->comparator = ssup_datum_signed_cmp;
2282 287 : PG_RETURN_VOID();
2283 : }
2284 :
2285 : /* note: this is used for timestamptz also */
2286 : static Datum
2287 0 : timestamp_decrement(Relation rel, Datum existing, bool *underflow)
2288 : {
2289 0 : Timestamp texisting = DatumGetTimestamp(existing);
2290 :
2291 0 : if (texisting == PG_INT64_MIN)
2292 : {
2293 : /* return value is undefined */
2294 0 : *underflow = true;
2295 0 : return (Datum) 0;
2296 : }
2297 :
2298 0 : *underflow = false;
2299 0 : return TimestampGetDatum(texisting - 1);
2300 : }
2301 :
2302 : /* note: this is used for timestamptz also */
2303 : static Datum
2304 0 : timestamp_increment(Relation rel, Datum existing, bool *overflow)
2305 : {
2306 0 : Timestamp texisting = DatumGetTimestamp(existing);
2307 :
2308 0 : if (texisting == PG_INT64_MAX)
2309 : {
2310 : /* return value is undefined */
2311 0 : *overflow = true;
2312 0 : return (Datum) 0;
2313 : }
2314 :
2315 0 : *overflow = false;
2316 0 : return TimestampGetDatum(texisting + 1);
2317 : }
2318 :
2319 : Datum
2320 0 : timestamp_skipsupport(PG_FUNCTION_ARGS)
2321 : {
2322 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
2323 :
2324 0 : sksup->decrement = timestamp_decrement;
2325 0 : sksup->increment = timestamp_increment;
2326 0 : sksup->low_elem = TimestampGetDatum(PG_INT64_MIN);
2327 0 : sksup->high_elem = TimestampGetDatum(PG_INT64_MAX);
2328 :
2329 0 : PG_RETURN_VOID();
2330 : }
2331 :
2332 : Datum
2333 3247 : timestamp_hash(PG_FUNCTION_ARGS)
2334 : {
2335 3247 : return hashint8(fcinfo);
2336 : }
2337 :
2338 : Datum
2339 30 : timestamp_hash_extended(PG_FUNCTION_ARGS)
2340 : {
2341 30 : return hashint8extended(fcinfo);
2342 : }
2343 :
2344 : Datum
2345 0 : timestamptz_hash(PG_FUNCTION_ARGS)
2346 : {
2347 0 : return hashint8(fcinfo);
2348 : }
2349 :
2350 : Datum
2351 0 : timestamptz_hash_extended(PG_FUNCTION_ARGS)
2352 : {
2353 0 : return hashint8extended(fcinfo);
2354 : }
2355 :
2356 : /*
2357 : * Cross-type comparison functions for timestamp vs timestamptz
2358 : */
2359 :
2360 : int32
2361 8037 : timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
2362 : {
2363 : TimestampTz dt1;
2364 8037 : ErrorSaveContext escontext = {T_ErrorSaveContext};
2365 :
2366 8037 : dt1 = timestamp2timestamptz_safe(timestampVal, (Node *) &escontext);
2367 8037 : if (escontext.error_occurred)
2368 : {
2369 6 : if (TIMESTAMP_IS_NOEND(dt1))
2370 : {
2371 : /* dt1 is larger than any finite timestamp, but less than infinity */
2372 0 : return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
2373 : }
2374 6 : if (TIMESTAMP_IS_NOBEGIN(dt1))
2375 : {
2376 : /* dt1 is less than any finite timestamp, but more than -infinity */
2377 6 : return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
2378 : }
2379 : }
2380 :
2381 8031 : return timestamptz_cmp_internal(dt1, dt2);
2382 : }
2383 :
2384 : Datum
2385 906 : timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
2386 : {
2387 906 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2388 906 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2389 :
2390 906 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) == 0);
2391 : }
2392 :
2393 : Datum
2394 0 : timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
2395 : {
2396 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2397 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2398 :
2399 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) != 0);
2400 : }
2401 :
2402 : Datum
2403 1602 : timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
2404 : {
2405 1602 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2406 1602 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2407 :
2408 1602 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) < 0);
2409 : }
2410 :
2411 : Datum
2412 1599 : timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
2413 : {
2414 1599 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2415 1599 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2416 :
2417 1599 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) > 0);
2418 : }
2419 :
2420 : Datum
2421 1899 : timestamp_le_timestamptz(PG_FUNCTION_ARGS)
2422 : {
2423 1899 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2424 1899 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2425 :
2426 1899 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) <= 0);
2427 : }
2428 :
2429 : Datum
2430 1752 : timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
2431 : {
2432 1752 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2433 1752 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2434 :
2435 1752 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) >= 0);
2436 : }
2437 :
2438 : Datum
2439 53 : timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
2440 : {
2441 53 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2442 53 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2443 :
2444 53 : PG_RETURN_INT32(timestamp_cmp_timestamptz_internal(timestampVal, dt2));
2445 : }
2446 :
2447 : Datum
2448 0 : timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
2449 : {
2450 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2451 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2452 :
2453 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) == 0);
2454 : }
2455 :
2456 : Datum
2457 48 : timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
2458 : {
2459 48 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2460 48 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2461 :
2462 48 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) != 0);
2463 : }
2464 :
2465 : Datum
2466 0 : timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
2467 : {
2468 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2469 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2470 :
2471 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) > 0);
2472 : }
2473 :
2474 : Datum
2475 0 : timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
2476 : {
2477 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2478 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2479 :
2480 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) < 0);
2481 : }
2482 :
2483 : Datum
2484 0 : timestamptz_le_timestamp(PG_FUNCTION_ARGS)
2485 : {
2486 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2487 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2488 :
2489 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) >= 0);
2490 : }
2491 :
2492 : Datum
2493 3 : timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
2494 : {
2495 3 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2496 3 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2497 :
2498 3 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) <= 0);
2499 : }
2500 :
2501 : Datum
2502 67 : timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
2503 : {
2504 67 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2505 67 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2506 :
2507 67 : PG_RETURN_INT32(-timestamp_cmp_timestamptz_internal(timestampVal, dt1));
2508 : }
2509 :
2510 :
2511 : /*
2512 : * interval_relop - is interval1 relop interval2
2513 : *
2514 : * Interval comparison is based on converting interval values to a linear
2515 : * representation expressed in the units of the time field (microseconds,
2516 : * in the case of integer timestamps) with days assumed to be always 24 hours
2517 : * and months assumed to be always 30 days. To avoid overflow, we need a
2518 : * wider-than-int64 datatype for the linear representation, so use INT128.
2519 : */
2520 :
2521 : static inline INT128
2522 138213 : interval_cmp_value(const Interval *interval)
2523 : {
2524 : INT128 span;
2525 : int64 days;
2526 :
2527 : /*
2528 : * Combine the month and day fields into an integral number of days.
2529 : * Because the inputs are int32, int64 arithmetic suffices here.
2530 : */
2531 138213 : days = interval->month * INT64CONST(30);
2532 138213 : days += interval->day;
2533 :
2534 : /* Widen time field to 128 bits */
2535 138213 : span = int64_to_int128(interval->time);
2536 :
2537 : /* Scale up days to microseconds, forming a 128-bit product */
2538 138213 : int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
2539 :
2540 138213 : return span;
2541 : }
2542 :
2543 : static int
2544 67300 : interval_cmp_internal(const Interval *interval1, const Interval *interval2)
2545 : {
2546 67300 : INT128 span1 = interval_cmp_value(interval1);
2547 67300 : INT128 span2 = interval_cmp_value(interval2);
2548 :
2549 67300 : return int128_compare(span1, span2);
2550 : }
2551 :
2552 : static int
2553 2444 : interval_sign(const Interval *interval)
2554 : {
2555 2444 : INT128 span = interval_cmp_value(interval);
2556 2444 : INT128 zero = int64_to_int128(0);
2557 :
2558 2444 : return int128_compare(span, zero);
2559 : }
2560 :
2561 : Datum
2562 7143 : interval_eq(PG_FUNCTION_ARGS)
2563 : {
2564 7143 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2565 7143 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2566 :
2567 7143 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
2568 : }
2569 :
2570 : Datum
2571 54 : interval_ne(PG_FUNCTION_ARGS)
2572 : {
2573 54 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2574 54 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2575 :
2576 54 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
2577 : }
2578 :
2579 : Datum
2580 15484 : interval_lt(PG_FUNCTION_ARGS)
2581 : {
2582 15484 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2583 15484 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2584 :
2585 15484 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
2586 : }
2587 :
2588 : Datum
2589 5663 : interval_gt(PG_FUNCTION_ARGS)
2590 : {
2591 5663 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2592 5663 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2593 :
2594 5663 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
2595 : }
2596 :
2597 : Datum
2598 3207 : interval_le(PG_FUNCTION_ARGS)
2599 : {
2600 3207 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2601 3207 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2602 :
2603 3207 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
2604 : }
2605 :
2606 : Datum
2607 2964 : interval_ge(PG_FUNCTION_ARGS)
2608 : {
2609 2964 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2610 2964 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2611 :
2612 2964 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
2613 : }
2614 :
2615 : Datum
2616 32341 : interval_cmp(PG_FUNCTION_ARGS)
2617 : {
2618 32341 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2619 32341 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2620 :
2621 32341 : PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
2622 : }
2623 :
2624 : /*
2625 : * Hashing for intervals
2626 : *
2627 : * We must produce equal hashvals for values that interval_cmp_internal()
2628 : * considers equal. So, compute the net span the same way it does,
2629 : * and then hash that.
2630 : */
2631 : Datum
2632 1139 : interval_hash(PG_FUNCTION_ARGS)
2633 : {
2634 1139 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2635 1139 : INT128 span = interval_cmp_value(interval);
2636 : int64 span64;
2637 :
2638 : /*
2639 : * Use only the least significant 64 bits for hashing. The upper 64 bits
2640 : * seldom add any useful information, and besides we must do it like this
2641 : * for compatibility with hashes calculated before use of INT128 was
2642 : * introduced.
2643 : */
2644 1139 : span64 = int128_to_int64(span);
2645 :
2646 1139 : return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
2647 : }
2648 :
2649 : Datum
2650 30 : interval_hash_extended(PG_FUNCTION_ARGS)
2651 : {
2652 30 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2653 30 : INT128 span = interval_cmp_value(interval);
2654 : int64 span64;
2655 :
2656 : /* Same approach as interval_hash */
2657 30 : span64 = int128_to_int64(span);
2658 :
2659 30 : return DirectFunctionCall2(hashint8extended, Int64GetDatumFast(span64),
2660 : PG_GETARG_DATUM(1));
2661 : }
2662 :
2663 : /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
2664 : *
2665 : * Algorithm is per SQL spec. This is much harder than you'd think
2666 : * because the spec requires us to deliver a non-null answer in some cases
2667 : * where some of the inputs are null.
2668 : */
2669 : Datum
2670 36 : overlaps_timestamp(PG_FUNCTION_ARGS)
2671 : {
2672 : /*
2673 : * The arguments are Timestamps, but we leave them as generic Datums to
2674 : * avoid unnecessary conversions between value and reference forms --- not
2675 : * to mention possible dereferences of null pointers.
2676 : */
2677 36 : Datum ts1 = PG_GETARG_DATUM(0);
2678 36 : Datum te1 = PG_GETARG_DATUM(1);
2679 36 : Datum ts2 = PG_GETARG_DATUM(2);
2680 36 : Datum te2 = PG_GETARG_DATUM(3);
2681 36 : bool ts1IsNull = PG_ARGISNULL(0);
2682 36 : bool te1IsNull = PG_ARGISNULL(1);
2683 36 : bool ts2IsNull = PG_ARGISNULL(2);
2684 36 : bool te2IsNull = PG_ARGISNULL(3);
2685 :
2686 : #define TIMESTAMP_GT(t1,t2) \
2687 : DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
2688 : #define TIMESTAMP_LT(t1,t2) \
2689 : DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
2690 :
2691 : /*
2692 : * If both endpoints of interval 1 are null, the result is null (unknown).
2693 : * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2694 : * take ts1 as the lesser endpoint.
2695 : */
2696 36 : if (ts1IsNull)
2697 : {
2698 0 : if (te1IsNull)
2699 0 : PG_RETURN_NULL();
2700 : /* swap null for non-null */
2701 0 : ts1 = te1;
2702 0 : te1IsNull = true;
2703 : }
2704 36 : else if (!te1IsNull)
2705 : {
2706 36 : if (TIMESTAMP_GT(ts1, te1))
2707 : {
2708 0 : Datum tt = ts1;
2709 :
2710 0 : ts1 = te1;
2711 0 : te1 = tt;
2712 : }
2713 : }
2714 :
2715 : /* Likewise for interval 2. */
2716 36 : if (ts2IsNull)
2717 : {
2718 0 : if (te2IsNull)
2719 0 : PG_RETURN_NULL();
2720 : /* swap null for non-null */
2721 0 : ts2 = te2;
2722 0 : te2IsNull = true;
2723 : }
2724 36 : else if (!te2IsNull)
2725 : {
2726 36 : if (TIMESTAMP_GT(ts2, te2))
2727 : {
2728 0 : Datum tt = ts2;
2729 :
2730 0 : ts2 = te2;
2731 0 : te2 = tt;
2732 : }
2733 : }
2734 :
2735 : /*
2736 : * At this point neither ts1 nor ts2 is null, so we can consider three
2737 : * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2738 : */
2739 36 : if (TIMESTAMP_GT(ts1, ts2))
2740 : {
2741 : /*
2742 : * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2743 : * in the presence of nulls it's not quite completely so.
2744 : */
2745 0 : if (te2IsNull)
2746 0 : PG_RETURN_NULL();
2747 0 : if (TIMESTAMP_LT(ts1, te2))
2748 0 : PG_RETURN_BOOL(true);
2749 0 : if (te1IsNull)
2750 0 : PG_RETURN_NULL();
2751 :
2752 : /*
2753 : * If te1 is not null then we had ts1 <= te1 above, and we just found
2754 : * ts1 >= te2, hence te1 >= te2.
2755 : */
2756 0 : PG_RETURN_BOOL(false);
2757 : }
2758 36 : else if (TIMESTAMP_LT(ts1, ts2))
2759 : {
2760 : /* This case is ts2 < te1 OR te2 < te1 */
2761 30 : if (te1IsNull)
2762 0 : PG_RETURN_NULL();
2763 30 : if (TIMESTAMP_LT(ts2, te1))
2764 12 : PG_RETURN_BOOL(true);
2765 18 : if (te2IsNull)
2766 0 : PG_RETURN_NULL();
2767 :
2768 : /*
2769 : * If te2 is not null then we had ts2 <= te2 above, and we just found
2770 : * ts2 >= te1, hence te2 >= te1.
2771 : */
2772 18 : PG_RETURN_BOOL(false);
2773 : }
2774 : else
2775 : {
2776 : /*
2777 : * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2778 : * rather silly way of saying "true if both are non-null, else null".
2779 : */
2780 6 : if (te1IsNull || te2IsNull)
2781 0 : PG_RETURN_NULL();
2782 6 : PG_RETURN_BOOL(true);
2783 : }
2784 :
2785 : #undef TIMESTAMP_GT
2786 : #undef TIMESTAMP_LT
2787 : }
2788 :
2789 :
2790 : /*----------------------------------------------------------
2791 : * "Arithmetic" operators on date/times.
2792 : *---------------------------------------------------------*/
2793 :
2794 : Datum
2795 0 : timestamp_smaller(PG_FUNCTION_ARGS)
2796 : {
2797 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2798 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2799 : Timestamp result;
2800 :
2801 : /* use timestamp_cmp_internal to be sure this agrees with comparisons */
2802 0 : if (timestamp_cmp_internal(dt1, dt2) < 0)
2803 0 : result = dt1;
2804 : else
2805 0 : result = dt2;
2806 0 : PG_RETURN_TIMESTAMP(result);
2807 : }
2808 :
2809 : Datum
2810 42 : timestamp_larger(PG_FUNCTION_ARGS)
2811 : {
2812 42 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2813 42 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2814 : Timestamp result;
2815 :
2816 42 : if (timestamp_cmp_internal(dt1, dt2) > 0)
2817 0 : result = dt1;
2818 : else
2819 42 : result = dt2;
2820 42 : PG_RETURN_TIMESTAMP(result);
2821 : }
2822 :
2823 :
2824 : Datum
2825 3227 : timestamp_mi(PG_FUNCTION_ARGS)
2826 : {
2827 3227 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2828 3227 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2829 : Interval *result;
2830 :
2831 3227 : result = palloc_object(Interval);
2832 :
2833 : /*
2834 : * Handle infinities.
2835 : *
2836 : * We treat anything that amounts to "infinity - infinity" as an error,
2837 : * since the interval type has nothing equivalent to NaN.
2838 : */
2839 3227 : if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
2840 : {
2841 42 : if (TIMESTAMP_IS_NOBEGIN(dt1))
2842 : {
2843 18 : if (TIMESTAMP_IS_NOBEGIN(dt2))
2844 6 : ereport(ERROR,
2845 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2846 : errmsg("interval out of range")));
2847 : else
2848 12 : INTERVAL_NOBEGIN(result);
2849 : }
2850 24 : else if (TIMESTAMP_IS_NOEND(dt1))
2851 : {
2852 24 : if (TIMESTAMP_IS_NOEND(dt2))
2853 6 : ereport(ERROR,
2854 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2855 : errmsg("interval out of range")));
2856 : else
2857 18 : INTERVAL_NOEND(result);
2858 : }
2859 0 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
2860 0 : INTERVAL_NOEND(result);
2861 : else /* TIMESTAMP_IS_NOEND(dt2) */
2862 0 : INTERVAL_NOBEGIN(result);
2863 :
2864 30 : PG_RETURN_INTERVAL_P(result);
2865 : }
2866 :
2867 3185 : if (unlikely(pg_sub_s64_overflow(dt1, dt2, &result->time)))
2868 6 : ereport(ERROR,
2869 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2870 : errmsg("interval out of range")));
2871 :
2872 3179 : result->month = 0;
2873 3179 : result->day = 0;
2874 :
2875 : /*----------
2876 : * This is wrong, but removing it breaks a lot of regression tests.
2877 : * For example:
2878 : *
2879 : * test=> SET timezone = 'EST5EDT';
2880 : * test=> SELECT
2881 : * test-> ('2005-10-30 13:22:00-05'::timestamptz -
2882 : * test(> '2005-10-29 13:22:00-04'::timestamptz);
2883 : * ?column?
2884 : * ----------------
2885 : * 1 day 01:00:00
2886 : * (1 row)
2887 : *
2888 : * so adding that to the first timestamp gets:
2889 : *
2890 : * test=> SELECT
2891 : * test-> ('2005-10-29 13:22:00-04'::timestamptz +
2892 : * test(> ('2005-10-30 13:22:00-05'::timestamptz -
2893 : * test(> '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
2894 : * timezone
2895 : * --------------------
2896 : * 2005-10-30 14:22:00
2897 : * (1 row)
2898 : *----------
2899 : */
2900 3179 : result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2901 : IntervalPGetDatum(result)));
2902 :
2903 3179 : PG_RETURN_INTERVAL_P(result);
2904 : }
2905 :
2906 : /*
2907 : * interval_justify_interval()
2908 : *
2909 : * Adjust interval so 'month', 'day', and 'time' portions are within
2910 : * customary bounds. Specifically:
2911 : *
2912 : * 0 <= abs(time) < 24 hours
2913 : * 0 <= abs(day) < 30 days
2914 : *
2915 : * Also, the sign bit on all three fields is made equal, so either
2916 : * all three fields are negative or all are positive.
2917 : */
2918 : Datum
2919 33 : interval_justify_interval(PG_FUNCTION_ARGS)
2920 : {
2921 33 : Interval *span = PG_GETARG_INTERVAL_P(0);
2922 : Interval *result;
2923 : TimeOffset wholeday;
2924 : int32 wholemonth;
2925 :
2926 33 : result = palloc_object(Interval);
2927 33 : result->month = span->month;
2928 33 : result->day = span->day;
2929 33 : result->time = span->time;
2930 :
2931 : /* do nothing for infinite intervals */
2932 33 : if (INTERVAL_NOT_FINITE(result))
2933 6 : PG_RETURN_INTERVAL_P(result);
2934 :
2935 : /* pre-justify days if it might prevent overflow */
2936 27 : if ((result->day > 0 && result->time > 0) ||
2937 24 : (result->day < 0 && result->time < 0))
2938 : {
2939 6 : wholemonth = result->day / DAYS_PER_MONTH;
2940 6 : result->day -= wholemonth * DAYS_PER_MONTH;
2941 6 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
2942 0 : ereport(ERROR,
2943 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2944 : errmsg("interval out of range")));
2945 : }
2946 :
2947 : /*
2948 : * Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8. If
2949 : * we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so
2950 : * this addition can't overflow. If we didn't pre-justify, then day and
2951 : * time are of different signs, so it still can't overflow.
2952 : */
2953 27 : TMODULO(result->time, wholeday, USECS_PER_DAY);
2954 27 : result->day += wholeday;
2955 :
2956 27 : wholemonth = result->day / DAYS_PER_MONTH;
2957 27 : result->day -= wholemonth * DAYS_PER_MONTH;
2958 27 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
2959 12 : ereport(ERROR,
2960 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2961 : errmsg("interval out of range")));
2962 :
2963 15 : if (result->month > 0 &&
2964 9 : (result->day < 0 || (result->day == 0 && result->time < 0)))
2965 : {
2966 3 : result->day += DAYS_PER_MONTH;
2967 3 : result->month--;
2968 : }
2969 12 : else if (result->month < 0 &&
2970 6 : (result->day > 0 || (result->day == 0 && result->time > 0)))
2971 : {
2972 0 : result->day -= DAYS_PER_MONTH;
2973 0 : result->month++;
2974 : }
2975 :
2976 15 : if (result->day > 0 && result->time < 0)
2977 : {
2978 3 : result->time += USECS_PER_DAY;
2979 3 : result->day--;
2980 : }
2981 12 : else if (result->day < 0 && result->time > 0)
2982 : {
2983 0 : result->time -= USECS_PER_DAY;
2984 0 : result->day++;
2985 : }
2986 :
2987 15 : PG_RETURN_INTERVAL_P(result);
2988 : }
2989 :
2990 : /*
2991 : * interval_justify_hours()
2992 : *
2993 : * Adjust interval so 'time' contains less than a whole day, adding
2994 : * the excess to 'day'. This is useful for
2995 : * situations (such as non-TZ) where '1 day' = '24 hours' is valid,
2996 : * e.g. interval subtraction and division.
2997 : */
2998 : Datum
2999 4181 : interval_justify_hours(PG_FUNCTION_ARGS)
3000 : {
3001 4181 : Interval *span = PG_GETARG_INTERVAL_P(0);
3002 : Interval *result;
3003 : TimeOffset wholeday;
3004 :
3005 4181 : result = palloc_object(Interval);
3006 4181 : result->month = span->month;
3007 4181 : result->day = span->day;
3008 4181 : result->time = span->time;
3009 :
3010 : /* do nothing for infinite intervals */
3011 4181 : if (INTERVAL_NOT_FINITE(result))
3012 6 : PG_RETURN_INTERVAL_P(result);
3013 :
3014 4175 : TMODULO(result->time, wholeday, USECS_PER_DAY);
3015 4175 : if (pg_add_s32_overflow(result->day, wholeday, &result->day))
3016 3 : ereport(ERROR,
3017 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3018 : errmsg("interval out of range")));
3019 :
3020 4172 : if (result->day > 0 && result->time < 0)
3021 : {
3022 0 : result->time += USECS_PER_DAY;
3023 0 : result->day--;
3024 : }
3025 4172 : else if (result->day < 0 && result->time > 0)
3026 : {
3027 0 : result->time -= USECS_PER_DAY;
3028 0 : result->day++;
3029 : }
3030 :
3031 4172 : PG_RETURN_INTERVAL_P(result);
3032 : }
3033 :
3034 : /*
3035 : * interval_justify_days()
3036 : *
3037 : * Adjust interval so 'day' contains less than 30 days, adding
3038 : * the excess to 'month'.
3039 : */
3040 : Datum
3041 1002 : interval_justify_days(PG_FUNCTION_ARGS)
3042 : {
3043 1002 : Interval *span = PG_GETARG_INTERVAL_P(0);
3044 : Interval *result;
3045 : int32 wholemonth;
3046 :
3047 1002 : result = palloc_object(Interval);
3048 1002 : result->month = span->month;
3049 1002 : result->day = span->day;
3050 1002 : result->time = span->time;
3051 :
3052 : /* do nothing for infinite intervals */
3053 1002 : if (INTERVAL_NOT_FINITE(result))
3054 6 : PG_RETURN_INTERVAL_P(result);
3055 :
3056 996 : wholemonth = result->day / DAYS_PER_MONTH;
3057 996 : result->day -= wholemonth * DAYS_PER_MONTH;
3058 996 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
3059 3 : ereport(ERROR,
3060 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3061 : errmsg("interval out of range")));
3062 :
3063 993 : if (result->month > 0 && result->day < 0)
3064 : {
3065 0 : result->day += DAYS_PER_MONTH;
3066 0 : result->month--;
3067 : }
3068 993 : else if (result->month < 0 && result->day > 0)
3069 : {
3070 0 : result->day -= DAYS_PER_MONTH;
3071 0 : result->month++;
3072 : }
3073 :
3074 993 : PG_RETURN_INTERVAL_P(result);
3075 : }
3076 :
3077 : /* timestamp_pl_interval()
3078 : * Add an interval to a timestamp data type.
3079 : * Note that interval has provisions for qualitative year/month and day
3080 : * units, so try to do the right thing with them.
3081 : * To add a month, increment the month, and use the same day of month.
3082 : * Then, if the next month has fewer days, set the day of month
3083 : * to the last day of month.
3084 : * To add a day, increment the mday, and use the same time of day.
3085 : * Lastly, add in the "quantitative time".
3086 : */
3087 : Datum
3088 4980 : timestamp_pl_interval(PG_FUNCTION_ARGS)
3089 : {
3090 4980 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3091 4980 : Interval *span = PG_GETARG_INTERVAL_P(1);
3092 : Timestamp result;
3093 :
3094 : /*
3095 : * Handle infinities.
3096 : *
3097 : * We treat anything that amounts to "infinity - infinity" as an error,
3098 : * since the timestamp type has nothing equivalent to NaN.
3099 : */
3100 4980 : if (INTERVAL_IS_NOBEGIN(span))
3101 : {
3102 138 : if (TIMESTAMP_IS_NOEND(timestamp))
3103 12 : ereport(ERROR,
3104 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3105 : errmsg("timestamp out of range")));
3106 : else
3107 126 : TIMESTAMP_NOBEGIN(result);
3108 : }
3109 4842 : else if (INTERVAL_IS_NOEND(span))
3110 : {
3111 102 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
3112 12 : ereport(ERROR,
3113 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3114 : errmsg("timestamp out of range")));
3115 : else
3116 90 : TIMESTAMP_NOEND(result);
3117 : }
3118 4740 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3119 57 : result = timestamp;
3120 : else
3121 : {
3122 4683 : if (span->month != 0)
3123 : {
3124 : struct pg_tm tt,
3125 1314 : *tm = &tt;
3126 : fsec_t fsec;
3127 :
3128 1314 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3129 0 : ereport(ERROR,
3130 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3131 : errmsg("timestamp out of range")));
3132 :
3133 1314 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3134 0 : ereport(ERROR,
3135 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3136 : errmsg("timestamp out of range")));
3137 1314 : if (tm->tm_mon > MONTHS_PER_YEAR)
3138 : {
3139 699 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3140 699 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3141 : }
3142 615 : else if (tm->tm_mon < 1)
3143 : {
3144 585 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3145 585 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3146 : }
3147 :
3148 : /* adjust for end of month boundary problems... */
3149 1314 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3150 6 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3151 :
3152 1314 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3153 0 : ereport(ERROR,
3154 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3155 : errmsg("timestamp out of range")));
3156 : }
3157 :
3158 4683 : if (span->day != 0)
3159 : {
3160 : struct pg_tm tt,
3161 1631 : *tm = &tt;
3162 : fsec_t fsec;
3163 : int julian;
3164 :
3165 1631 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3166 0 : ereport(ERROR,
3167 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3168 : errmsg("timestamp out of range")));
3169 :
3170 : /*
3171 : * Add days by converting to and from Julian. We need an overflow
3172 : * check here since j2date expects a non-negative integer input.
3173 : */
3174 1631 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3175 1631 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3176 1631 : julian < 0)
3177 3 : ereport(ERROR,
3178 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3179 : errmsg("timestamp out of range")));
3180 1628 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3181 :
3182 1628 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3183 0 : ereport(ERROR,
3184 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3185 : errmsg("timestamp out of range")));
3186 : }
3187 :
3188 4680 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3189 3 : ereport(ERROR,
3190 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3191 : errmsg("timestamp out of range")));
3192 :
3193 4677 : if (!IS_VALID_TIMESTAMP(timestamp))
3194 0 : ereport(ERROR,
3195 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3196 : errmsg("timestamp out of range")));
3197 :
3198 4677 : result = timestamp;
3199 : }
3200 :
3201 4950 : PG_RETURN_TIMESTAMP(result);
3202 : }
3203 :
3204 : Datum
3205 1086 : timestamp_mi_interval(PG_FUNCTION_ARGS)
3206 : {
3207 1086 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3208 1086 : Interval *span = PG_GETARG_INTERVAL_P(1);
3209 : Interval tspan;
3210 :
3211 1086 : interval_um_internal(span, &tspan);
3212 :
3213 1086 : return DirectFunctionCall2(timestamp_pl_interval,
3214 : TimestampGetDatum(timestamp),
3215 : PointerGetDatum(&tspan));
3216 : }
3217 :
3218 :
3219 : /* timestamptz_pl_interval_internal()
3220 : * Add an interval to a timestamptz, in the given (or session) timezone.
3221 : *
3222 : * Note that interval has provisions for qualitative year/month and day
3223 : * units, so try to do the right thing with them.
3224 : * To add a month, increment the month, and use the same day of month.
3225 : * Then, if the next month has fewer days, set the day of month
3226 : * to the last day of month.
3227 : * To add a day, increment the mday, and use the same time of day.
3228 : * Lastly, add in the "quantitative time".
3229 : */
3230 : static TimestampTz
3231 75996 : timestamptz_pl_interval_internal(TimestampTz timestamp,
3232 : Interval *span,
3233 : pg_tz *attimezone)
3234 : {
3235 : TimestampTz result;
3236 : int tz;
3237 :
3238 : /*
3239 : * Handle infinities.
3240 : *
3241 : * We treat anything that amounts to "infinity - infinity" as an error,
3242 : * since the timestamptz type has nothing equivalent to NaN.
3243 : */
3244 75996 : if (INTERVAL_IS_NOBEGIN(span))
3245 : {
3246 216 : if (TIMESTAMP_IS_NOEND(timestamp))
3247 6 : ereport(ERROR,
3248 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3249 : errmsg("timestamp out of range")));
3250 : else
3251 210 : TIMESTAMP_NOBEGIN(result);
3252 : }
3253 75780 : else if (INTERVAL_IS_NOEND(span))
3254 : {
3255 180 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
3256 6 : ereport(ERROR,
3257 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3258 : errmsg("timestamp out of range")));
3259 : else
3260 174 : TIMESTAMP_NOEND(result);
3261 : }
3262 75600 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3263 60 : result = timestamp;
3264 : else
3265 : {
3266 : /* Use session timezone if caller asks for default */
3267 75540 : if (attimezone == NULL)
3268 44236 : attimezone = session_timezone;
3269 :
3270 75540 : if (span->month != 0)
3271 : {
3272 : struct pg_tm tt,
3273 27924 : *tm = &tt;
3274 : fsec_t fsec;
3275 :
3276 27924 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3277 0 : ereport(ERROR,
3278 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3279 : errmsg("timestamp out of range")));
3280 :
3281 27924 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3282 0 : ereport(ERROR,
3283 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3284 : errmsg("timestamp out of range")));
3285 27924 : if (tm->tm_mon > MONTHS_PER_YEAR)
3286 : {
3287 27033 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3288 27033 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3289 : }
3290 891 : else if (tm->tm_mon < 1)
3291 : {
3292 678 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3293 678 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3294 : }
3295 :
3296 : /* adjust for end of month boundary problems... */
3297 27924 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3298 27 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3299 :
3300 27924 : tz = DetermineTimeZoneOffset(tm, attimezone);
3301 :
3302 27924 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3303 0 : ereport(ERROR,
3304 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3305 : errmsg("timestamp out of range")));
3306 : }
3307 :
3308 75540 : if (span->day != 0)
3309 : {
3310 : struct pg_tm tt,
3311 1827 : *tm = &tt;
3312 : fsec_t fsec;
3313 : int julian;
3314 :
3315 1827 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3316 0 : ereport(ERROR,
3317 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3318 : errmsg("timestamp out of range")));
3319 :
3320 : /*
3321 : * Add days by converting to and from Julian. We need an overflow
3322 : * check here since j2date expects a non-negative integer input.
3323 : * In practice though, it will give correct answers for small
3324 : * negative Julian dates; we should allow -1 to avoid
3325 : * timezone-dependent failures, as discussed in timestamp.h.
3326 : */
3327 1827 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3328 1827 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3329 1827 : julian < -1)
3330 3 : ereport(ERROR,
3331 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3332 : errmsg("timestamp out of range")));
3333 1824 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3334 :
3335 1824 : tz = DetermineTimeZoneOffset(tm, attimezone);
3336 :
3337 1824 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3338 0 : ereport(ERROR,
3339 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3340 : errmsg("timestamp out of range")));
3341 : }
3342 :
3343 75537 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3344 3 : ereport(ERROR,
3345 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3346 : errmsg("timestamp out of range")));
3347 :
3348 75534 : if (!IS_VALID_TIMESTAMP(timestamp))
3349 0 : ereport(ERROR,
3350 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3351 : errmsg("timestamp out of range")));
3352 :
3353 75534 : result = timestamp;
3354 : }
3355 :
3356 75978 : return result;
3357 : }
3358 :
3359 : /* timestamptz_mi_interval_internal()
3360 : * As above, but subtract the interval.
3361 : */
3362 : static TimestampTz
3363 1059 : timestamptz_mi_interval_internal(TimestampTz timestamp,
3364 : Interval *span,
3365 : pg_tz *attimezone)
3366 : {
3367 : Interval tspan;
3368 :
3369 1059 : interval_um_internal(span, &tspan);
3370 :
3371 1059 : return timestamptz_pl_interval_internal(timestamp, &tspan, attimezone);
3372 : }
3373 :
3374 : /* timestamptz_pl_interval()
3375 : * Add an interval to a timestamptz, in the session timezone.
3376 : */
3377 : Datum
3378 43429 : timestamptz_pl_interval(PG_FUNCTION_ARGS)
3379 : {
3380 43429 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3381 43429 : Interval *span = PG_GETARG_INTERVAL_P(1);
3382 :
3383 43429 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, NULL));
3384 : }
3385 :
3386 : Datum
3387 816 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
3388 : {
3389 816 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3390 816 : Interval *span = PG_GETARG_INTERVAL_P(1);
3391 :
3392 816 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, NULL));
3393 : }
3394 :
3395 : /* timestamptz_pl_interval_at_zone()
3396 : * Add an interval to a timestamptz, in the specified timezone.
3397 : */
3398 : Datum
3399 3 : timestamptz_pl_interval_at_zone(PG_FUNCTION_ARGS)
3400 : {
3401 3 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3402 3 : Interval *span = PG_GETARG_INTERVAL_P(1);
3403 3 : text *zone = PG_GETARG_TEXT_PP(2);
3404 3 : pg_tz *attimezone = lookup_timezone(zone);
3405 :
3406 3 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, attimezone));
3407 : }
3408 :
3409 : Datum
3410 3 : timestamptz_mi_interval_at_zone(PG_FUNCTION_ARGS)
3411 : {
3412 3 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3413 3 : Interval *span = PG_GETARG_INTERVAL_P(1);
3414 3 : text *zone = PG_GETARG_TEXT_PP(2);
3415 3 : pg_tz *attimezone = lookup_timezone(zone);
3416 :
3417 3 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, attimezone));
3418 : }
3419 :
3420 : /* interval_um_internal()
3421 : * Negate an interval.
3422 : */
3423 : static void
3424 4020 : interval_um_internal(const Interval *interval, Interval *result)
3425 : {
3426 4020 : if (INTERVAL_IS_NOBEGIN(interval))
3427 135 : INTERVAL_NOEND(result);
3428 3885 : else if (INTERVAL_IS_NOEND(interval))
3429 339 : INTERVAL_NOBEGIN(result);
3430 : else
3431 : {
3432 : /* Negate each field, guarding against overflow */
3433 7089 : if (pg_sub_s64_overflow(INT64CONST(0), interval->time, &result->time) ||
3434 7083 : pg_sub_s32_overflow(0, interval->day, &result->day) ||
3435 3540 : pg_sub_s32_overflow(0, interval->month, &result->month) ||
3436 3537 : INTERVAL_NOT_FINITE(result))
3437 15 : ereport(ERROR,
3438 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3439 : errmsg("interval out of range")));
3440 : }
3441 4005 : }
3442 :
3443 : Datum
3444 1857 : interval_um(PG_FUNCTION_ARGS)
3445 : {
3446 1857 : Interval *interval = PG_GETARG_INTERVAL_P(0);
3447 : Interval *result;
3448 :
3449 1857 : result = palloc_object(Interval);
3450 1857 : interval_um_internal(interval, result);
3451 :
3452 1842 : PG_RETURN_INTERVAL_P(result);
3453 : }
3454 :
3455 :
3456 : Datum
3457 0 : interval_smaller(PG_FUNCTION_ARGS)
3458 : {
3459 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3460 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3461 : Interval *result;
3462 :
3463 : /* use interval_cmp_internal to be sure this agrees with comparisons */
3464 0 : if (interval_cmp_internal(interval1, interval2) < 0)
3465 0 : result = interval1;
3466 : else
3467 0 : result = interval2;
3468 0 : PG_RETURN_INTERVAL_P(result);
3469 : }
3470 :
3471 : Datum
3472 0 : interval_larger(PG_FUNCTION_ARGS)
3473 : {
3474 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3475 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3476 : Interval *result;
3477 :
3478 0 : if (interval_cmp_internal(interval1, interval2) > 0)
3479 0 : result = interval1;
3480 : else
3481 0 : result = interval2;
3482 0 : PG_RETURN_INTERVAL_P(result);
3483 : }
3484 :
3485 : static void
3486 264 : finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result)
3487 : {
3488 : Assert(!INTERVAL_NOT_FINITE(span1));
3489 : Assert(!INTERVAL_NOT_FINITE(span2));
3490 :
3491 528 : if (pg_add_s32_overflow(span1->month, span2->month, &result->month) ||
3492 528 : pg_add_s32_overflow(span1->day, span2->day, &result->day) ||
3493 264 : pg_add_s64_overflow(span1->time, span2->time, &result->time) ||
3494 264 : INTERVAL_NOT_FINITE(result))
3495 6 : ereport(ERROR,
3496 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3497 : errmsg("interval out of range")));
3498 258 : }
3499 :
3500 : Datum
3501 279 : interval_pl(PG_FUNCTION_ARGS)
3502 : {
3503 279 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3504 279 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3505 : Interval *result;
3506 :
3507 279 : result = palloc_object(Interval);
3508 :
3509 : /*
3510 : * Handle infinities.
3511 : *
3512 : * We treat anything that amounts to "infinity - infinity" as an error,
3513 : * since the interval type has nothing equivalent to NaN.
3514 : */
3515 279 : if (INTERVAL_IS_NOBEGIN(span1))
3516 : {
3517 27 : if (INTERVAL_IS_NOEND(span2))
3518 3 : ereport(ERROR,
3519 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3520 : errmsg("interval out of range")));
3521 : else
3522 24 : INTERVAL_NOBEGIN(result);
3523 : }
3524 252 : else if (INTERVAL_IS_NOEND(span1))
3525 : {
3526 21 : if (INTERVAL_IS_NOBEGIN(span2))
3527 3 : ereport(ERROR,
3528 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3529 : errmsg("interval out of range")));
3530 : else
3531 18 : INTERVAL_NOEND(result);
3532 : }
3533 231 : else if (INTERVAL_NOT_FINITE(span2))
3534 69 : memcpy(result, span2, sizeof(Interval));
3535 : else
3536 162 : finite_interval_pl(span1, span2, result);
3537 :
3538 267 : PG_RETURN_INTERVAL_P(result);
3539 : }
3540 :
3541 : static void
3542 774 : finite_interval_mi(const Interval *span1, const Interval *span2, Interval *result)
3543 : {
3544 : Assert(!INTERVAL_NOT_FINITE(span1));
3545 : Assert(!INTERVAL_NOT_FINITE(span2));
3546 :
3547 1548 : if (pg_sub_s32_overflow(span1->month, span2->month, &result->month) ||
3548 1548 : pg_sub_s32_overflow(span1->day, span2->day, &result->day) ||
3549 774 : pg_sub_s64_overflow(span1->time, span2->time, &result->time) ||
3550 774 : INTERVAL_NOT_FINITE(result))
3551 6 : ereport(ERROR,
3552 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3553 : errmsg("interval out of range")));
3554 768 : }
3555 :
3556 : Datum
3557 897 : interval_mi(PG_FUNCTION_ARGS)
3558 : {
3559 897 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3560 897 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3561 : Interval *result;
3562 :
3563 897 : result = palloc_object(Interval);
3564 :
3565 : /*
3566 : * Handle infinities.
3567 : *
3568 : * We treat anything that amounts to "infinity - infinity" as an error,
3569 : * since the interval type has nothing equivalent to NaN.
3570 : */
3571 897 : if (INTERVAL_IS_NOBEGIN(span1))
3572 : {
3573 27 : if (INTERVAL_IS_NOBEGIN(span2))
3574 3 : ereport(ERROR,
3575 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3576 : errmsg("interval out of range")));
3577 : else
3578 24 : INTERVAL_NOBEGIN(result);
3579 : }
3580 870 : else if (INTERVAL_IS_NOEND(span1))
3581 : {
3582 24 : if (INTERVAL_IS_NOEND(span2))
3583 3 : ereport(ERROR,
3584 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3585 : errmsg("interval out of range")));
3586 : else
3587 21 : INTERVAL_NOEND(result);
3588 : }
3589 846 : else if (INTERVAL_IS_NOBEGIN(span2))
3590 3 : INTERVAL_NOEND(result);
3591 843 : else if (INTERVAL_IS_NOEND(span2))
3592 93 : INTERVAL_NOBEGIN(result);
3593 : else
3594 750 : finite_interval_mi(span1, span2, result);
3595 :
3596 885 : PG_RETURN_INTERVAL_P(result);
3597 : }
3598 :
3599 : /*
3600 : * There is no interval_abs(): it is unclear what value to return:
3601 : * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3602 : * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3603 : */
3604 :
3605 : Datum
3606 5826 : interval_mul(PG_FUNCTION_ARGS)
3607 : {
3608 5826 : Interval *span = PG_GETARG_INTERVAL_P(0);
3609 5826 : float8 factor = PG_GETARG_FLOAT8(1);
3610 : double month_remainder_days,
3611 : sec_remainder,
3612 : result_double;
3613 5826 : int32 orig_month = span->month,
3614 5826 : orig_day = span->day;
3615 : Interval *result;
3616 :
3617 5826 : result = palloc_object(Interval);
3618 :
3619 : /*
3620 : * Handle NaN and infinities.
3621 : *
3622 : * We treat "0 * infinity" and "infinity * 0" as errors, since the
3623 : * interval type has nothing equivalent to NaN.
3624 : */
3625 5826 : if (isnan(factor))
3626 6 : goto out_of_range;
3627 :
3628 5820 : if (INTERVAL_NOT_FINITE(span))
3629 : {
3630 30 : if (factor == 0.0)
3631 6 : goto out_of_range;
3632 :
3633 24 : if (factor < 0.0)
3634 12 : interval_um_internal(span, result);
3635 : else
3636 12 : memcpy(result, span, sizeof(Interval));
3637 :
3638 24 : PG_RETURN_INTERVAL_P(result);
3639 : }
3640 5790 : if (isinf(factor))
3641 : {
3642 12 : int isign = interval_sign(span);
3643 :
3644 12 : if (isign == 0)
3645 6 : goto out_of_range;
3646 :
3647 6 : if (factor * isign < 0)
3648 3 : INTERVAL_NOBEGIN(result);
3649 : else
3650 3 : INTERVAL_NOEND(result);
3651 :
3652 6 : PG_RETURN_INTERVAL_P(result);
3653 : }
3654 :
3655 5778 : result_double = span->month * factor;
3656 5778 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3657 3 : goto out_of_range;
3658 5775 : result->month = (int32) result_double;
3659 :
3660 5775 : result_double = span->day * factor;
3661 5775 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3662 3 : goto out_of_range;
3663 5772 : result->day = (int32) result_double;
3664 :
3665 : /*
3666 : * The above correctly handles the whole-number part of the month and day
3667 : * products, but we have to do something with any fractional part
3668 : * resulting when the factor is non-integral. We cascade the fractions
3669 : * down to lower units using the conversion factors DAYS_PER_MONTH and
3670 : * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
3671 : * so by the representation. The user can choose to cascade up later,
3672 : * using justify_hours and/or justify_days.
3673 : */
3674 :
3675 : /*
3676 : * Fractional months full days into days.
3677 : *
3678 : * Floating point calculation are inherently imprecise, so these
3679 : * calculations are crafted to produce the most reliable result possible.
3680 : * TSROUND() is needed to more accurately produce whole numbers where
3681 : * appropriate.
3682 : */
3683 5772 : month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
3684 5772 : month_remainder_days = TSROUND(month_remainder_days);
3685 5772 : sec_remainder = (orig_day * factor - result->day +
3686 5772 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3687 5772 : sec_remainder = TSROUND(sec_remainder);
3688 :
3689 : /*
3690 : * Might have 24:00:00 hours due to rounding, or >24 hours because of time
3691 : * cascade from months and days. It might still be >24 if the combination
3692 : * of cascade and the seconds factor operation itself.
3693 : */
3694 5772 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3695 : {
3696 0 : if (pg_add_s32_overflow(result->day,
3697 0 : (int) (sec_remainder / SECS_PER_DAY),
3698 : &result->day))
3699 0 : goto out_of_range;
3700 0 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3701 : }
3702 :
3703 : /* cascade units down */
3704 5772 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3705 : &result->day))
3706 3 : goto out_of_range;
3707 5769 : result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
3708 5769 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3709 3 : goto out_of_range;
3710 5766 : result->time = (int64) result_double;
3711 :
3712 5766 : if (INTERVAL_NOT_FINITE(result))
3713 3 : goto out_of_range;
3714 :
3715 5763 : PG_RETURN_INTERVAL_P(result);
3716 :
3717 33 : out_of_range:
3718 33 : ereport(ERROR,
3719 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3720 : errmsg("interval out of range"));
3721 :
3722 : PG_RETURN_NULL(); /* keep compiler quiet */
3723 : }
3724 :
3725 : Datum
3726 5715 : mul_d_interval(PG_FUNCTION_ARGS)
3727 : {
3728 : /* Args are float8 and Interval *, but leave them as generic Datum */
3729 5715 : Datum factor = PG_GETARG_DATUM(0);
3730 5715 : Datum span = PG_GETARG_DATUM(1);
3731 :
3732 5715 : return DirectFunctionCall2(interval_mul, span, factor);
3733 : }
3734 :
3735 : Datum
3736 111 : interval_div(PG_FUNCTION_ARGS)
3737 : {
3738 111 : Interval *span = PG_GETARG_INTERVAL_P(0);
3739 111 : float8 factor = PG_GETARG_FLOAT8(1);
3740 : double month_remainder_days,
3741 : sec_remainder,
3742 : result_double;
3743 111 : int32 orig_month = span->month,
3744 111 : orig_day = span->day;
3745 : Interval *result;
3746 :
3747 111 : result = palloc_object(Interval);
3748 :
3749 111 : if (factor == 0.0)
3750 0 : ereport(ERROR,
3751 : (errcode(ERRCODE_DIVISION_BY_ZERO),
3752 : errmsg("division by zero")));
3753 :
3754 : /*
3755 : * Handle NaN and infinities.
3756 : *
3757 : * We treat "infinity / infinity" as an error, since the interval type has
3758 : * nothing equivalent to NaN. Otherwise, dividing by infinity is handled
3759 : * by the regular division code, causing all fields to be set to zero.
3760 : */
3761 111 : if (isnan(factor))
3762 6 : goto out_of_range;
3763 :
3764 105 : if (INTERVAL_NOT_FINITE(span))
3765 : {
3766 24 : if (isinf(factor))
3767 12 : goto out_of_range;
3768 :
3769 12 : if (factor < 0.0)
3770 6 : interval_um_internal(span, result);
3771 : else
3772 6 : memcpy(result, span, sizeof(Interval));
3773 :
3774 12 : PG_RETURN_INTERVAL_P(result);
3775 : }
3776 :
3777 81 : result_double = span->month / factor;
3778 81 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3779 3 : goto out_of_range;
3780 78 : result->month = (int32) result_double;
3781 :
3782 78 : result_double = span->day / factor;
3783 78 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3784 3 : goto out_of_range;
3785 75 : result->day = (int32) result_double;
3786 :
3787 : /*
3788 : * Fractional months full days into days. See comment in interval_mul().
3789 : */
3790 75 : month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
3791 75 : month_remainder_days = TSROUND(month_remainder_days);
3792 75 : sec_remainder = (orig_day / factor - result->day +
3793 75 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3794 75 : sec_remainder = TSROUND(sec_remainder);
3795 75 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3796 : {
3797 3 : if (pg_add_s32_overflow(result->day,
3798 3 : (int) (sec_remainder / SECS_PER_DAY),
3799 : &result->day))
3800 0 : goto out_of_range;
3801 3 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3802 : }
3803 :
3804 : /* cascade units down */
3805 75 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3806 : &result->day))
3807 0 : goto out_of_range;
3808 75 : result_double = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
3809 75 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3810 3 : goto out_of_range;
3811 72 : result->time = (int64) result_double;
3812 :
3813 72 : if (INTERVAL_NOT_FINITE(result))
3814 3 : goto out_of_range;
3815 :
3816 69 : PG_RETURN_INTERVAL_P(result);
3817 :
3818 30 : out_of_range:
3819 30 : ereport(ERROR,
3820 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3821 : errmsg("interval out of range"));
3822 :
3823 : PG_RETURN_NULL(); /* keep compiler quiet */
3824 : }
3825 :
3826 :
3827 : /*
3828 : * in_range support functions for timestamps and intervals.
3829 : *
3830 : * Per SQL spec, we support these with interval as the offset type.
3831 : * The spec's restriction that the offset not be negative is a bit hard to
3832 : * decipher for intervals, but we choose to interpret it the same as our
3833 : * interval comparison operators would.
3834 : */
3835 :
3836 : Datum
3837 567 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
3838 : {
3839 567 : TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
3840 567 : TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
3841 567 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3842 567 : bool sub = PG_GETARG_BOOL(3);
3843 567 : bool less = PG_GETARG_BOOL(4);
3844 : TimestampTz sum;
3845 :
3846 567 : if (interval_sign(offset) < 0)
3847 6 : ereport(ERROR,
3848 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3849 : errmsg("invalid preceding or following size in window function")));
3850 :
3851 : /*
3852 : * Deal with cases where both base and offset are infinite, and computing
3853 : * base +/- offset would cause an error. As for float and numeric types,
3854 : * we assume that all values infinitely precede +infinity and infinitely
3855 : * follow -infinity. See in_range_float8_float8() for reasoning.
3856 : */
3857 561 : if (INTERVAL_IS_NOEND(offset) &&
3858 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3859 114 : PG_RETURN_BOOL(true);
3860 :
3861 : /* We don't currently bother to avoid overflow hazards here */
3862 447 : if (sub)
3863 240 : sum = timestamptz_mi_interval_internal(base, offset, NULL);
3864 : else
3865 207 : sum = timestamptz_pl_interval_internal(base, offset, NULL);
3866 :
3867 447 : if (less)
3868 177 : PG_RETURN_BOOL(val <= sum);
3869 : else
3870 270 : PG_RETURN_BOOL(val >= sum);
3871 : }
3872 :
3873 : Datum
3874 1233 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
3875 : {
3876 1233 : Timestamp val = PG_GETARG_TIMESTAMP(0);
3877 1233 : Timestamp base = PG_GETARG_TIMESTAMP(1);
3878 1233 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3879 1233 : bool sub = PG_GETARG_BOOL(3);
3880 1233 : bool less = PG_GETARG_BOOL(4);
3881 : Timestamp sum;
3882 :
3883 1233 : if (interval_sign(offset) < 0)
3884 9 : ereport(ERROR,
3885 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3886 : errmsg("invalid preceding or following size in window function")));
3887 :
3888 : /*
3889 : * Deal with cases where both base and offset are infinite, and computing
3890 : * base +/- offset would cause an error. As for float and numeric types,
3891 : * we assume that all values infinitely precede +infinity and infinitely
3892 : * follow -infinity. See in_range_float8_float8() for reasoning.
3893 : */
3894 1224 : if (INTERVAL_IS_NOEND(offset) &&
3895 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3896 114 : PG_RETURN_BOOL(true);
3897 :
3898 : /* We don't currently bother to avoid overflow hazards here */
3899 1110 : if (sub)
3900 516 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
3901 : TimestampGetDatum(base),
3902 : IntervalPGetDatum(offset)));
3903 : else
3904 594 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
3905 : TimestampGetDatum(base),
3906 : IntervalPGetDatum(offset)));
3907 :
3908 1110 : if (less)
3909 603 : PG_RETURN_BOOL(val <= sum);
3910 : else
3911 507 : PG_RETURN_BOOL(val >= sum);
3912 : }
3913 :
3914 : Datum
3915 564 : in_range_interval_interval(PG_FUNCTION_ARGS)
3916 : {
3917 564 : Interval *val = PG_GETARG_INTERVAL_P(0);
3918 564 : Interval *base = PG_GETARG_INTERVAL_P(1);
3919 564 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3920 564 : bool sub = PG_GETARG_BOOL(3);
3921 564 : bool less = PG_GETARG_BOOL(4);
3922 : Interval *sum;
3923 :
3924 564 : if (interval_sign(offset) < 0)
3925 6 : ereport(ERROR,
3926 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3927 : errmsg("invalid preceding or following size in window function")));
3928 :
3929 : /*
3930 : * Deal with cases where both base and offset are infinite, and computing
3931 : * base +/- offset would cause an error. As for float and numeric types,
3932 : * we assume that all values infinitely precede +infinity and infinitely
3933 : * follow -infinity. See in_range_float8_float8() for reasoning.
3934 : */
3935 840 : if (INTERVAL_IS_NOEND(offset) &&
3936 282 : (sub ? INTERVAL_IS_NOEND(base) : INTERVAL_IS_NOBEGIN(base)))
3937 114 : PG_RETURN_BOOL(true);
3938 :
3939 : /* We don't currently bother to avoid overflow hazards here */
3940 444 : if (sub)
3941 240 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
3942 : IntervalPGetDatum(base),
3943 : IntervalPGetDatum(offset)));
3944 : else
3945 204 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
3946 : IntervalPGetDatum(base),
3947 : IntervalPGetDatum(offset)));
3948 :
3949 444 : if (less)
3950 174 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3951 : else
3952 270 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3953 : }
3954 :
3955 :
3956 : /*
3957 : * Prepare state data for an interval aggregate function, that needs to compute
3958 : * sum and count, in the aggregate's memory context.
3959 : *
3960 : * The function is used when the state data needs to be allocated in aggregate's
3961 : * context. When the state data needs to be allocated in the current memory
3962 : * context, we use palloc0 directly e.g. interval_avg_deserialize().
3963 : */
3964 : static IntervalAggState *
3965 27 : makeIntervalAggState(FunctionCallInfo fcinfo)
3966 : {
3967 : IntervalAggState *state;
3968 : MemoryContext agg_context;
3969 : MemoryContext old_context;
3970 :
3971 27 : if (!AggCheckCallContext(fcinfo, &agg_context))
3972 0 : elog(ERROR, "aggregate function called in non-aggregate context");
3973 :
3974 27 : old_context = MemoryContextSwitchTo(agg_context);
3975 :
3976 27 : state = palloc0_object(IntervalAggState);
3977 :
3978 27 : MemoryContextSwitchTo(old_context);
3979 :
3980 27 : return state;
3981 : }
3982 :
3983 : /*
3984 : * Accumulate a new input value for interval aggregate functions.
3985 : */
3986 : static void
3987 162 : do_interval_accum(IntervalAggState *state, Interval *newval)
3988 : {
3989 : /* Infinite inputs are counted separately, and do not affect "N" */
3990 162 : if (INTERVAL_IS_NOBEGIN(newval))
3991 : {
3992 30 : state->nInfcount++;
3993 30 : return;
3994 : }
3995 :
3996 132 : if (INTERVAL_IS_NOEND(newval))
3997 : {
3998 30 : state->pInfcount++;
3999 30 : return;
4000 : }
4001 :
4002 102 : finite_interval_pl(&state->sumX, newval, &state->sumX);
4003 102 : state->N++;
4004 : }
4005 :
4006 : /*
4007 : * Remove the given interval value from the aggregated state.
4008 : */
4009 : static void
4010 102 : do_interval_discard(IntervalAggState *state, Interval *newval)
4011 : {
4012 : /* Infinite inputs are counted separately, and do not affect "N" */
4013 102 : if (INTERVAL_IS_NOBEGIN(newval))
4014 : {
4015 12 : state->nInfcount--;
4016 12 : return;
4017 : }
4018 :
4019 90 : if (INTERVAL_IS_NOEND(newval))
4020 : {
4021 24 : state->pInfcount--;
4022 24 : return;
4023 : }
4024 :
4025 : /* Handle the to-be-discarded finite value. */
4026 66 : state->N--;
4027 66 : if (state->N > 0)
4028 24 : finite_interval_mi(&state->sumX, newval, &state->sumX);
4029 : else
4030 : {
4031 : /* All values discarded, reset the state */
4032 : Assert(state->N == 0);
4033 42 : memset(&state->sumX, 0, sizeof(state->sumX));
4034 : }
4035 : }
4036 :
4037 : /*
4038 : * Transition function for sum() and avg() interval aggregates.
4039 : */
4040 : Datum
4041 204 : interval_avg_accum(PG_FUNCTION_ARGS)
4042 : {
4043 : IntervalAggState *state;
4044 :
4045 204 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4046 :
4047 : /* Create the state data on the first call */
4048 204 : if (state == NULL)
4049 27 : state = makeIntervalAggState(fcinfo);
4050 :
4051 204 : if (!PG_ARGISNULL(1))
4052 162 : do_interval_accum(state, PG_GETARG_INTERVAL_P(1));
4053 :
4054 204 : PG_RETURN_POINTER(state);
4055 : }
4056 :
4057 : /*
4058 : * Combine function for sum() and avg() interval aggregates.
4059 : *
4060 : * Combine the given internal aggregate states and place the combination in
4061 : * the first argument.
4062 : */
4063 : Datum
4064 0 : interval_avg_combine(PG_FUNCTION_ARGS)
4065 : {
4066 : IntervalAggState *state1;
4067 : IntervalAggState *state2;
4068 :
4069 0 : state1 = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4070 0 : state2 = PG_ARGISNULL(1) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(1);
4071 :
4072 0 : if (state2 == NULL)
4073 0 : PG_RETURN_POINTER(state1);
4074 :
4075 0 : if (state1 == NULL)
4076 : {
4077 : /* manually copy all fields from state2 to state1 */
4078 0 : state1 = makeIntervalAggState(fcinfo);
4079 :
4080 0 : state1->N = state2->N;
4081 0 : state1->pInfcount = state2->pInfcount;
4082 0 : state1->nInfcount = state2->nInfcount;
4083 :
4084 0 : state1->sumX.day = state2->sumX.day;
4085 0 : state1->sumX.month = state2->sumX.month;
4086 0 : state1->sumX.time = state2->sumX.time;
4087 :
4088 0 : PG_RETURN_POINTER(state1);
4089 : }
4090 :
4091 0 : state1->N += state2->N;
4092 0 : state1->pInfcount += state2->pInfcount;
4093 0 : state1->nInfcount += state2->nInfcount;
4094 :
4095 : /* Accumulate finite interval values, if any. */
4096 0 : if (state2->N > 0)
4097 0 : finite_interval_pl(&state1->sumX, &state2->sumX, &state1->sumX);
4098 :
4099 0 : PG_RETURN_POINTER(state1);
4100 : }
4101 :
4102 : /*
4103 : * interval_avg_serialize
4104 : * Serialize IntervalAggState for interval aggregates.
4105 : */
4106 : Datum
4107 0 : interval_avg_serialize(PG_FUNCTION_ARGS)
4108 : {
4109 : IntervalAggState *state;
4110 : StringInfoData buf;
4111 : bytea *result;
4112 :
4113 : /* Ensure we disallow calling when not in aggregate context */
4114 0 : if (!AggCheckCallContext(fcinfo, NULL))
4115 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4116 :
4117 0 : state = (IntervalAggState *) PG_GETARG_POINTER(0);
4118 :
4119 0 : pq_begintypsend(&buf);
4120 :
4121 : /* N */
4122 0 : pq_sendint64(&buf, state->N);
4123 :
4124 : /* sumX */
4125 0 : pq_sendint64(&buf, state->sumX.time);
4126 0 : pq_sendint32(&buf, state->sumX.day);
4127 0 : pq_sendint32(&buf, state->sumX.month);
4128 :
4129 : /* pInfcount */
4130 0 : pq_sendint64(&buf, state->pInfcount);
4131 :
4132 : /* nInfcount */
4133 0 : pq_sendint64(&buf, state->nInfcount);
4134 :
4135 0 : result = pq_endtypsend(&buf);
4136 :
4137 0 : PG_RETURN_BYTEA_P(result);
4138 : }
4139 :
4140 : /*
4141 : * interval_avg_deserialize
4142 : * Deserialize bytea into IntervalAggState for interval aggregates.
4143 : */
4144 : Datum
4145 0 : interval_avg_deserialize(PG_FUNCTION_ARGS)
4146 : {
4147 : bytea *sstate;
4148 : IntervalAggState *result;
4149 : StringInfoData buf;
4150 :
4151 0 : if (!AggCheckCallContext(fcinfo, NULL))
4152 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4153 :
4154 0 : sstate = PG_GETARG_BYTEA_PP(0);
4155 :
4156 : /*
4157 : * Initialize a StringInfo so that we can "receive" it using the standard
4158 : * recv-function infrastructure.
4159 : */
4160 0 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
4161 0 : VARSIZE_ANY_EXHDR(sstate));
4162 :
4163 0 : result = palloc0_object(IntervalAggState);
4164 :
4165 : /* N */
4166 0 : result->N = pq_getmsgint64(&buf);
4167 :
4168 : /* sumX */
4169 0 : result->sumX.time = pq_getmsgint64(&buf);
4170 0 : result->sumX.day = pq_getmsgint(&buf, 4);
4171 0 : result->sumX.month = pq_getmsgint(&buf, 4);
4172 :
4173 : /* pInfcount */
4174 0 : result->pInfcount = pq_getmsgint64(&buf);
4175 :
4176 : /* nInfcount */
4177 0 : result->nInfcount = pq_getmsgint64(&buf);
4178 :
4179 0 : pq_getmsgend(&buf);
4180 :
4181 0 : PG_RETURN_POINTER(result);
4182 : }
4183 :
4184 : /*
4185 : * Inverse transition function for sum() and avg() interval aggregates.
4186 : */
4187 : Datum
4188 132 : interval_avg_accum_inv(PG_FUNCTION_ARGS)
4189 : {
4190 : IntervalAggState *state;
4191 :
4192 132 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4193 :
4194 : /* Should not get here with no state */
4195 132 : if (state == NULL)
4196 0 : elog(ERROR, "interval_avg_accum_inv called with NULL state");
4197 :
4198 132 : if (!PG_ARGISNULL(1))
4199 102 : do_interval_discard(state, PG_GETARG_INTERVAL_P(1));
4200 :
4201 132 : PG_RETURN_POINTER(state);
4202 : }
4203 :
4204 : /* avg(interval) aggregate final function */
4205 : Datum
4206 84 : interval_avg(PG_FUNCTION_ARGS)
4207 : {
4208 : IntervalAggState *state;
4209 :
4210 84 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4211 :
4212 : /* If there were no non-null inputs, return NULL */
4213 84 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4214 9 : PG_RETURN_NULL();
4215 :
4216 : /*
4217 : * Aggregating infinities that all have the same sign produces infinity
4218 : * with that sign. Aggregating infinities with different signs results in
4219 : * an error.
4220 : */
4221 75 : if (state->pInfcount > 0 || state->nInfcount > 0)
4222 : {
4223 : Interval *result;
4224 :
4225 54 : if (state->pInfcount > 0 && state->nInfcount > 0)
4226 3 : ereport(ERROR,
4227 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4228 : errmsg("interval out of range")));
4229 :
4230 51 : result = palloc_object(Interval);
4231 51 : if (state->pInfcount > 0)
4232 30 : INTERVAL_NOEND(result);
4233 : else
4234 21 : INTERVAL_NOBEGIN(result);
4235 :
4236 51 : PG_RETURN_INTERVAL_P(result);
4237 : }
4238 :
4239 21 : return DirectFunctionCall2(interval_div,
4240 : IntervalPGetDatum(&state->sumX),
4241 : Float8GetDatum((double) state->N));
4242 : }
4243 :
4244 : /* sum(interval) aggregate final function */
4245 : Datum
4246 81 : interval_sum(PG_FUNCTION_ARGS)
4247 : {
4248 : IntervalAggState *state;
4249 : Interval *result;
4250 :
4251 81 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4252 :
4253 : /* If there were no non-null inputs, return NULL */
4254 81 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4255 9 : PG_RETURN_NULL();
4256 :
4257 : /*
4258 : * Aggregating infinities that all have the same sign produces infinity
4259 : * with that sign. Aggregating infinities with different signs results in
4260 : * an error.
4261 : */
4262 72 : if (state->pInfcount > 0 && state->nInfcount > 0)
4263 3 : ereport(ERROR,
4264 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4265 : errmsg("interval out of range")));
4266 :
4267 69 : result = palloc_object(Interval);
4268 :
4269 69 : if (state->pInfcount > 0)
4270 30 : INTERVAL_NOEND(result);
4271 39 : else if (state->nInfcount > 0)
4272 21 : INTERVAL_NOBEGIN(result);
4273 : else
4274 18 : memcpy(result, &state->sumX, sizeof(Interval));
4275 :
4276 69 : PG_RETURN_INTERVAL_P(result);
4277 : }
4278 :
4279 : /* timestamp_age()
4280 : * Calculate time difference while retaining year/month fields.
4281 : * Note that this does not result in an accurate absolute time span
4282 : * since year and month are out of context once the arithmetic
4283 : * is done.
4284 : */
4285 : Datum
4286 18 : timestamp_age(PG_FUNCTION_ARGS)
4287 : {
4288 18 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
4289 18 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
4290 : Interval *result;
4291 : fsec_t fsec1,
4292 : fsec2;
4293 : struct pg_itm tt,
4294 18 : *tm = &tt;
4295 : struct pg_tm tt1,
4296 18 : *tm1 = &tt1;
4297 : struct pg_tm tt2,
4298 18 : *tm2 = &tt2;
4299 :
4300 18 : result = palloc_object(Interval);
4301 :
4302 : /*
4303 : * Handle infinities.
4304 : *
4305 : * We treat anything that amounts to "infinity - infinity" as an error,
4306 : * since the interval type has nothing equivalent to NaN.
4307 : */
4308 18 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4309 : {
4310 6 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4311 3 : ereport(ERROR,
4312 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4313 : errmsg("interval out of range")));
4314 : else
4315 3 : INTERVAL_NOBEGIN(result);
4316 : }
4317 12 : else if (TIMESTAMP_IS_NOEND(dt1))
4318 : {
4319 6 : if (TIMESTAMP_IS_NOEND(dt2))
4320 3 : ereport(ERROR,
4321 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4322 : errmsg("interval out of range")));
4323 : else
4324 3 : INTERVAL_NOEND(result);
4325 : }
4326 6 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4327 3 : INTERVAL_NOEND(result);
4328 3 : else if (TIMESTAMP_IS_NOEND(dt2))
4329 3 : INTERVAL_NOBEGIN(result);
4330 0 : else if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
4331 0 : timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
4332 : {
4333 : /* form the symbolic difference */
4334 0 : tm->tm_usec = fsec1 - fsec2;
4335 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4336 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4337 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4338 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4339 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4340 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4341 :
4342 : /* flip sign if necessary... */
4343 0 : if (dt1 < dt2)
4344 : {
4345 0 : tm->tm_usec = -tm->tm_usec;
4346 0 : tm->tm_sec = -tm->tm_sec;
4347 0 : tm->tm_min = -tm->tm_min;
4348 0 : tm->tm_hour = -tm->tm_hour;
4349 0 : tm->tm_mday = -tm->tm_mday;
4350 0 : tm->tm_mon = -tm->tm_mon;
4351 0 : tm->tm_year = -tm->tm_year;
4352 : }
4353 :
4354 : /* propagate any negative fields into the next higher field */
4355 0 : while (tm->tm_usec < 0)
4356 : {
4357 0 : tm->tm_usec += USECS_PER_SEC;
4358 0 : tm->tm_sec--;
4359 : }
4360 :
4361 0 : while (tm->tm_sec < 0)
4362 : {
4363 0 : tm->tm_sec += SECS_PER_MINUTE;
4364 0 : tm->tm_min--;
4365 : }
4366 :
4367 0 : while (tm->tm_min < 0)
4368 : {
4369 0 : tm->tm_min += MINS_PER_HOUR;
4370 0 : tm->tm_hour--;
4371 : }
4372 :
4373 0 : while (tm->tm_hour < 0)
4374 : {
4375 0 : tm->tm_hour += HOURS_PER_DAY;
4376 0 : tm->tm_mday--;
4377 : }
4378 :
4379 0 : while (tm->tm_mday < 0)
4380 : {
4381 0 : if (dt1 < dt2)
4382 : {
4383 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4384 0 : tm->tm_mon--;
4385 : }
4386 : else
4387 : {
4388 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4389 0 : tm->tm_mon--;
4390 : }
4391 : }
4392 :
4393 0 : while (tm->tm_mon < 0)
4394 : {
4395 0 : tm->tm_mon += MONTHS_PER_YEAR;
4396 0 : tm->tm_year--;
4397 : }
4398 :
4399 : /* recover sign if necessary... */
4400 0 : if (dt1 < dt2)
4401 : {
4402 0 : tm->tm_usec = -tm->tm_usec;
4403 0 : tm->tm_sec = -tm->tm_sec;
4404 0 : tm->tm_min = -tm->tm_min;
4405 0 : tm->tm_hour = -tm->tm_hour;
4406 0 : tm->tm_mday = -tm->tm_mday;
4407 0 : tm->tm_mon = -tm->tm_mon;
4408 0 : tm->tm_year = -tm->tm_year;
4409 : }
4410 :
4411 0 : if (itm2interval(tm, result) != 0)
4412 0 : ereport(ERROR,
4413 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4414 : errmsg("interval out of range")));
4415 : }
4416 : else
4417 0 : ereport(ERROR,
4418 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4419 : errmsg("timestamp out of range")));
4420 :
4421 12 : PG_RETURN_INTERVAL_P(result);
4422 : }
4423 :
4424 :
4425 : /* timestamptz_age()
4426 : * Calculate time difference while retaining year/month fields.
4427 : * Note that this does not result in an accurate absolute time span
4428 : * since year and month are out of context once the arithmetic
4429 : * is done.
4430 : */
4431 : Datum
4432 18 : timestamptz_age(PG_FUNCTION_ARGS)
4433 : {
4434 18 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
4435 18 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
4436 : Interval *result;
4437 : fsec_t fsec1,
4438 : fsec2;
4439 : struct pg_itm tt,
4440 18 : *tm = &tt;
4441 : struct pg_tm tt1,
4442 18 : *tm1 = &tt1;
4443 : struct pg_tm tt2,
4444 18 : *tm2 = &tt2;
4445 : int tz1;
4446 : int tz2;
4447 :
4448 18 : result = palloc_object(Interval);
4449 :
4450 : /*
4451 : * Handle infinities.
4452 : *
4453 : * We treat anything that amounts to "infinity - infinity" as an error,
4454 : * since the interval type has nothing equivalent to NaN.
4455 : */
4456 18 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4457 : {
4458 6 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4459 3 : ereport(ERROR,
4460 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4461 : errmsg("interval out of range")));
4462 : else
4463 3 : INTERVAL_NOBEGIN(result);
4464 : }
4465 12 : else if (TIMESTAMP_IS_NOEND(dt1))
4466 : {
4467 6 : if (TIMESTAMP_IS_NOEND(dt2))
4468 3 : ereport(ERROR,
4469 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4470 : errmsg("interval out of range")));
4471 : else
4472 3 : INTERVAL_NOEND(result);
4473 : }
4474 6 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4475 3 : INTERVAL_NOEND(result);
4476 3 : else if (TIMESTAMP_IS_NOEND(dt2))
4477 3 : INTERVAL_NOBEGIN(result);
4478 0 : else if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
4479 0 : timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
4480 : {
4481 : /* form the symbolic difference */
4482 0 : tm->tm_usec = fsec1 - fsec2;
4483 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4484 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4485 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4486 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4487 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4488 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4489 :
4490 : /* flip sign if necessary... */
4491 0 : if (dt1 < dt2)
4492 : {
4493 0 : tm->tm_usec = -tm->tm_usec;
4494 0 : tm->tm_sec = -tm->tm_sec;
4495 0 : tm->tm_min = -tm->tm_min;
4496 0 : tm->tm_hour = -tm->tm_hour;
4497 0 : tm->tm_mday = -tm->tm_mday;
4498 0 : tm->tm_mon = -tm->tm_mon;
4499 0 : tm->tm_year = -tm->tm_year;
4500 : }
4501 :
4502 : /* propagate any negative fields into the next higher field */
4503 0 : while (tm->tm_usec < 0)
4504 : {
4505 0 : tm->tm_usec += USECS_PER_SEC;
4506 0 : tm->tm_sec--;
4507 : }
4508 :
4509 0 : while (tm->tm_sec < 0)
4510 : {
4511 0 : tm->tm_sec += SECS_PER_MINUTE;
4512 0 : tm->tm_min--;
4513 : }
4514 :
4515 0 : while (tm->tm_min < 0)
4516 : {
4517 0 : tm->tm_min += MINS_PER_HOUR;
4518 0 : tm->tm_hour--;
4519 : }
4520 :
4521 0 : while (tm->tm_hour < 0)
4522 : {
4523 0 : tm->tm_hour += HOURS_PER_DAY;
4524 0 : tm->tm_mday--;
4525 : }
4526 :
4527 0 : while (tm->tm_mday < 0)
4528 : {
4529 0 : if (dt1 < dt2)
4530 : {
4531 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4532 0 : tm->tm_mon--;
4533 : }
4534 : else
4535 : {
4536 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4537 0 : tm->tm_mon--;
4538 : }
4539 : }
4540 :
4541 0 : while (tm->tm_mon < 0)
4542 : {
4543 0 : tm->tm_mon += MONTHS_PER_YEAR;
4544 0 : tm->tm_year--;
4545 : }
4546 :
4547 : /*
4548 : * Note: we deliberately ignore any difference between tz1 and tz2.
4549 : */
4550 :
4551 : /* recover sign if necessary... */
4552 0 : if (dt1 < dt2)
4553 : {
4554 0 : tm->tm_usec = -tm->tm_usec;
4555 0 : tm->tm_sec = -tm->tm_sec;
4556 0 : tm->tm_min = -tm->tm_min;
4557 0 : tm->tm_hour = -tm->tm_hour;
4558 0 : tm->tm_mday = -tm->tm_mday;
4559 0 : tm->tm_mon = -tm->tm_mon;
4560 0 : tm->tm_year = -tm->tm_year;
4561 : }
4562 :
4563 0 : if (itm2interval(tm, result) != 0)
4564 0 : ereport(ERROR,
4565 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4566 : errmsg("interval out of range")));
4567 : }
4568 : else
4569 0 : ereport(ERROR,
4570 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4571 : errmsg("timestamp out of range")));
4572 :
4573 12 : PG_RETURN_INTERVAL_P(result);
4574 : }
4575 :
4576 :
4577 : /*----------------------------------------------------------
4578 : * Conversion operators.
4579 : *---------------------------------------------------------*/
4580 :
4581 :
4582 : /* timestamp_bin()
4583 : * Bin timestamp into specified interval.
4584 : */
4585 : Datum
4586 138 : timestamp_bin(PG_FUNCTION_ARGS)
4587 : {
4588 138 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4589 138 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4590 138 : Timestamp origin = PG_GETARG_TIMESTAMP(2);
4591 : Timestamp result,
4592 : stride_usecs,
4593 : tm_diff,
4594 : tm_modulo,
4595 : tm_delta;
4596 :
4597 138 : if (TIMESTAMP_NOT_FINITE(timestamp))
4598 0 : PG_RETURN_TIMESTAMP(timestamp);
4599 :
4600 138 : if (TIMESTAMP_NOT_FINITE(origin))
4601 0 : ereport(ERROR,
4602 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4603 : errmsg("origin out of range")));
4604 :
4605 138 : if (INTERVAL_NOT_FINITE(stride))
4606 6 : ereport(ERROR,
4607 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4608 : errmsg("timestamps cannot be binned into infinite intervals")));
4609 :
4610 132 : if (stride->month != 0)
4611 6 : ereport(ERROR,
4612 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4613 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4614 :
4615 126 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4616 123 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4617 3 : ereport(ERROR,
4618 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4619 : errmsg("interval out of range")));
4620 :
4621 123 : if (stride_usecs <= 0)
4622 6 : ereport(ERROR,
4623 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4624 : errmsg("stride must be greater than zero")));
4625 :
4626 117 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4627 3 : ereport(ERROR,
4628 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4629 : errmsg("interval out of range")));
4630 :
4631 : /* These calculations cannot overflow */
4632 114 : tm_modulo = tm_diff % stride_usecs;
4633 114 : tm_delta = tm_diff - tm_modulo;
4634 114 : result = origin + tm_delta;
4635 :
4636 : /*
4637 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4638 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4639 : * since the result might now be out of the range origin .. timestamp.
4640 : */
4641 114 : if (tm_modulo < 0)
4642 : {
4643 39 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4644 39 : !IS_VALID_TIMESTAMP(result))
4645 3 : ereport(ERROR,
4646 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4647 : errmsg("timestamp out of range")));
4648 : }
4649 :
4650 111 : PG_RETURN_TIMESTAMP(result);
4651 : }
4652 :
4653 : /* timestamp_trunc()
4654 : * Truncate timestamp to specified units.
4655 : */
4656 : Datum
4657 705 : timestamp_trunc(PG_FUNCTION_ARGS)
4658 : {
4659 705 : text *units = PG_GETARG_TEXT_PP(0);
4660 705 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4661 : Timestamp result;
4662 : int type,
4663 : val;
4664 : char *lowunits;
4665 : fsec_t fsec;
4666 : struct pg_tm tt,
4667 705 : *tm = &tt;
4668 :
4669 705 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4670 705 : VARSIZE_ANY_EXHDR(units),
4671 : false);
4672 :
4673 705 : type = DecodeUnits(0, lowunits, &val);
4674 :
4675 705 : if (type == UNITS)
4676 : {
4677 702 : if (TIMESTAMP_NOT_FINITE(timestamp))
4678 : {
4679 : /*
4680 : * Errors thrown here for invalid units should exactly match those
4681 : * below, else there will be unexpected discrepancies between
4682 : * finite- and infinite-input cases.
4683 : */
4684 6 : switch (val)
4685 : {
4686 3 : case DTK_WEEK:
4687 : case DTK_MILLENNIUM:
4688 : case DTK_CENTURY:
4689 : case DTK_DECADE:
4690 : case DTK_YEAR:
4691 : case DTK_QUARTER:
4692 : case DTK_MONTH:
4693 : case DTK_DAY:
4694 : case DTK_HOUR:
4695 : case DTK_MINUTE:
4696 : case DTK_SECOND:
4697 : case DTK_MILLISEC:
4698 : case DTK_MICROSEC:
4699 3 : PG_RETURN_TIMESTAMP(timestamp);
4700 : break;
4701 3 : default:
4702 3 : ereport(ERROR,
4703 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4704 : errmsg("unit \"%s\" not supported for type %s",
4705 : lowunits, format_type_be(TIMESTAMPOID))));
4706 : result = 0;
4707 : }
4708 : }
4709 :
4710 696 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4711 0 : ereport(ERROR,
4712 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4713 : errmsg("timestamp out of range")));
4714 :
4715 696 : switch (val)
4716 : {
4717 15 : case DTK_WEEK:
4718 : {
4719 : int woy;
4720 :
4721 15 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4722 :
4723 : /*
4724 : * If it is week 52/53 and the month is January, then the
4725 : * week must belong to the previous year. Also, some
4726 : * December dates belong to the next year.
4727 : */
4728 15 : if (woy >= 52 && tm->tm_mon == 1)
4729 0 : --tm->tm_year;
4730 15 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4731 0 : ++tm->tm_year;
4732 15 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4733 15 : tm->tm_hour = 0;
4734 15 : tm->tm_min = 0;
4735 15 : tm->tm_sec = 0;
4736 15 : fsec = 0;
4737 15 : break;
4738 : }
4739 3 : case DTK_MILLENNIUM:
4740 : /* see comments in timestamptz_trunc */
4741 3 : if (tm->tm_year > 0)
4742 3 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4743 : else
4744 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4745 : pg_fallthrough;
4746 : case DTK_CENTURY:
4747 : /* see comments in timestamptz_trunc */
4748 6 : if (tm->tm_year > 0)
4749 6 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4750 : else
4751 0 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4752 : pg_fallthrough;
4753 : case DTK_DECADE:
4754 : /* see comments in timestamptz_trunc */
4755 6 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4756 : {
4757 0 : if (tm->tm_year > 0)
4758 0 : tm->tm_year = (tm->tm_year / 10) * 10;
4759 : else
4760 0 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4761 : }
4762 : pg_fallthrough;
4763 : case DTK_YEAR:
4764 6 : tm->tm_mon = 1;
4765 : pg_fallthrough;
4766 6 : case DTK_QUARTER:
4767 6 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4768 : pg_fallthrough;
4769 6 : case DTK_MONTH:
4770 6 : tm->tm_mday = 1;
4771 : pg_fallthrough;
4772 618 : case DTK_DAY:
4773 618 : tm->tm_hour = 0;
4774 : pg_fallthrough;
4775 630 : case DTK_HOUR:
4776 630 : tm->tm_min = 0;
4777 : pg_fallthrough;
4778 642 : case DTK_MINUTE:
4779 642 : tm->tm_sec = 0;
4780 : pg_fallthrough;
4781 654 : case DTK_SECOND:
4782 654 : fsec = 0;
4783 654 : break;
4784 :
4785 12 : case DTK_MILLISEC:
4786 12 : fsec = (fsec / 1000) * 1000;
4787 12 : break;
4788 :
4789 12 : case DTK_MICROSEC:
4790 12 : break;
4791 :
4792 3 : default:
4793 3 : ereport(ERROR,
4794 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4795 : errmsg("unit \"%s\" not supported for type %s",
4796 : lowunits, format_type_be(TIMESTAMPOID))));
4797 : result = 0;
4798 : }
4799 :
4800 693 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
4801 0 : ereport(ERROR,
4802 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4803 : errmsg("timestamp out of range")));
4804 : }
4805 : else
4806 : {
4807 3 : ereport(ERROR,
4808 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4809 : errmsg("unit \"%s\" not recognized for type %s",
4810 : lowunits, format_type_be(TIMESTAMPOID))));
4811 : result = 0;
4812 : }
4813 :
4814 693 : PG_RETURN_TIMESTAMP(result);
4815 : }
4816 :
4817 : /* timestamptz_bin()
4818 : * Bin timestamptz into specified interval using specified origin.
4819 : */
4820 : Datum
4821 66 : timestamptz_bin(PG_FUNCTION_ARGS)
4822 : {
4823 66 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4824 66 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
4825 66 : TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
4826 : TimestampTz result,
4827 : stride_usecs,
4828 : tm_diff,
4829 : tm_modulo,
4830 : tm_delta;
4831 :
4832 66 : if (TIMESTAMP_NOT_FINITE(timestamp))
4833 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
4834 :
4835 66 : if (TIMESTAMP_NOT_FINITE(origin))
4836 0 : ereport(ERROR,
4837 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4838 : errmsg("origin out of range")));
4839 :
4840 66 : if (INTERVAL_NOT_FINITE(stride))
4841 0 : ereport(ERROR,
4842 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4843 : errmsg("timestamps cannot be binned into infinite intervals")));
4844 :
4845 66 : if (stride->month != 0)
4846 6 : ereport(ERROR,
4847 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4848 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4849 :
4850 60 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4851 57 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4852 3 : ereport(ERROR,
4853 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4854 : errmsg("interval out of range")));
4855 :
4856 57 : if (stride_usecs <= 0)
4857 6 : ereport(ERROR,
4858 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4859 : errmsg("stride must be greater than zero")));
4860 :
4861 51 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4862 3 : ereport(ERROR,
4863 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4864 : errmsg("interval out of range")));
4865 :
4866 : /* These calculations cannot overflow */
4867 48 : tm_modulo = tm_diff % stride_usecs;
4868 48 : tm_delta = tm_diff - tm_modulo;
4869 48 : result = origin + tm_delta;
4870 :
4871 : /*
4872 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4873 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4874 : * since the result might now be out of the range origin .. timestamp.
4875 : */
4876 48 : if (tm_modulo < 0)
4877 : {
4878 3 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4879 3 : !IS_VALID_TIMESTAMP(result))
4880 3 : ereport(ERROR,
4881 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4882 : errmsg("timestamp out of range")));
4883 : }
4884 :
4885 45 : PG_RETURN_TIMESTAMPTZ(result);
4886 : }
4887 :
4888 : /*
4889 : * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
4890 : *
4891 : * tzp identifies the zone to truncate with respect to. We assume
4892 : * infinite timestamps have already been rejected.
4893 : */
4894 : static TimestampTz
4895 675 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
4896 : {
4897 : TimestampTz result;
4898 : int tz;
4899 : int type,
4900 : val;
4901 675 : bool redotz = false;
4902 : char *lowunits;
4903 : fsec_t fsec;
4904 : struct pg_tm tt,
4905 675 : *tm = &tt;
4906 :
4907 675 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4908 675 : VARSIZE_ANY_EXHDR(units),
4909 : false);
4910 :
4911 675 : type = DecodeUnits(0, lowunits, &val);
4912 :
4913 675 : if (type == UNITS)
4914 : {
4915 669 : if (TIMESTAMP_NOT_FINITE(timestamp))
4916 : {
4917 : /*
4918 : * Errors thrown here for invalid units should exactly match those
4919 : * below, else there will be unexpected discrepancies between
4920 : * finite- and infinite-input cases.
4921 : */
4922 12 : switch (val)
4923 : {
4924 6 : case DTK_WEEK:
4925 : case DTK_MILLENNIUM:
4926 : case DTK_CENTURY:
4927 : case DTK_DECADE:
4928 : case DTK_YEAR:
4929 : case DTK_QUARTER:
4930 : case DTK_MONTH:
4931 : case DTK_DAY:
4932 : case DTK_HOUR:
4933 : case DTK_MINUTE:
4934 : case DTK_SECOND:
4935 : case DTK_MILLISEC:
4936 : case DTK_MICROSEC:
4937 6 : return timestamp;
4938 : break;
4939 :
4940 6 : default:
4941 6 : ereport(ERROR,
4942 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4943 : errmsg("unit \"%s\" not supported for type %s",
4944 : lowunits, format_type_be(TIMESTAMPTZOID))));
4945 : result = 0;
4946 : }
4947 : }
4948 :
4949 657 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
4950 0 : ereport(ERROR,
4951 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4952 : errmsg("timestamp out of range")));
4953 :
4954 657 : switch (val)
4955 : {
4956 3 : case DTK_WEEK:
4957 : {
4958 : int woy;
4959 :
4960 3 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4961 :
4962 : /*
4963 : * If it is week 52/53 and the month is January, then the
4964 : * week must belong to the previous year. Also, some
4965 : * December dates belong to the next year.
4966 : */
4967 3 : if (woy >= 52 && tm->tm_mon == 1)
4968 0 : --tm->tm_year;
4969 3 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4970 0 : ++tm->tm_year;
4971 3 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4972 3 : tm->tm_hour = 0;
4973 3 : tm->tm_min = 0;
4974 3 : tm->tm_sec = 0;
4975 3 : fsec = 0;
4976 3 : redotz = true;
4977 3 : break;
4978 : }
4979 : /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
4980 3 : case DTK_MILLENNIUM:
4981 :
4982 : /*
4983 : * truncating to the millennium? what is this supposed to
4984 : * mean? let us put the first year of the millennium... i.e.
4985 : * -1000, 1, 1001, 2001...
4986 : */
4987 3 : if (tm->tm_year > 0)
4988 3 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4989 : else
4990 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4991 : pg_fallthrough;
4992 : case DTK_CENTURY:
4993 : /* truncating to the century? as above: -100, 1, 101... */
4994 15 : if (tm->tm_year > 0)
4995 12 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4996 : else
4997 3 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4998 : pg_fallthrough;
4999 : case DTK_DECADE:
5000 :
5001 : /*
5002 : * truncating to the decade? first year of the decade. must
5003 : * not be applied if year was truncated before!
5004 : */
5005 24 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
5006 : {
5007 9 : if (tm->tm_year > 0)
5008 6 : tm->tm_year = (tm->tm_year / 10) * 10;
5009 : else
5010 3 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
5011 : }
5012 : pg_fallthrough;
5013 : case DTK_YEAR:
5014 24 : tm->tm_mon = 1;
5015 : pg_fallthrough;
5016 24 : case DTK_QUARTER:
5017 24 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
5018 : pg_fallthrough;
5019 24 : case DTK_MONTH:
5020 24 : tm->tm_mday = 1;
5021 : pg_fallthrough;
5022 636 : case DTK_DAY:
5023 636 : tm->tm_hour = 0;
5024 636 : redotz = true; /* for all cases >= DAY */
5025 : pg_fallthrough;
5026 639 : case DTK_HOUR:
5027 639 : tm->tm_min = 0;
5028 : pg_fallthrough;
5029 642 : case DTK_MINUTE:
5030 642 : tm->tm_sec = 0;
5031 : pg_fallthrough;
5032 645 : case DTK_SECOND:
5033 645 : fsec = 0;
5034 645 : break;
5035 3 : case DTK_MILLISEC:
5036 3 : fsec = (fsec / 1000) * 1000;
5037 3 : break;
5038 3 : case DTK_MICROSEC:
5039 3 : break;
5040 :
5041 3 : default:
5042 3 : ereport(ERROR,
5043 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5044 : errmsg("unit \"%s\" not supported for type %s",
5045 : lowunits, format_type_be(TIMESTAMPTZOID))));
5046 : result = 0;
5047 : }
5048 :
5049 654 : if (redotz)
5050 639 : tz = DetermineTimeZoneOffset(tm, tzp);
5051 :
5052 654 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
5053 0 : ereport(ERROR,
5054 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5055 : errmsg("timestamp out of range")));
5056 : }
5057 : else
5058 : {
5059 6 : ereport(ERROR,
5060 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5061 : errmsg("unit \"%s\" not recognized for type %s",
5062 : lowunits, format_type_be(TIMESTAMPTZOID))));
5063 : result = 0;
5064 : }
5065 :
5066 654 : return result;
5067 : }
5068 :
5069 : /* timestamptz_trunc()
5070 : * Truncate timestamptz to specified units in session timezone.
5071 : */
5072 : Datum
5073 639 : timestamptz_trunc(PG_FUNCTION_ARGS)
5074 : {
5075 639 : text *units = PG_GETARG_TEXT_PP(0);
5076 639 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5077 : TimestampTz result;
5078 :
5079 639 : result = timestamptz_trunc_internal(units, timestamp, session_timezone);
5080 :
5081 630 : PG_RETURN_TIMESTAMPTZ(result);
5082 : }
5083 :
5084 : /* timestamptz_trunc_zone()
5085 : * Truncate timestamptz to specified units in specified timezone.
5086 : */
5087 : Datum
5088 36 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
5089 : {
5090 36 : text *units = PG_GETARG_TEXT_PP(0);
5091 36 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5092 36 : text *zone = PG_GETARG_TEXT_PP(2);
5093 : TimestampTz result;
5094 : pg_tz *tzp;
5095 :
5096 : /*
5097 : * Look up the requested timezone.
5098 : */
5099 36 : tzp = lookup_timezone(zone);
5100 :
5101 36 : result = timestamptz_trunc_internal(units, timestamp, tzp);
5102 :
5103 30 : PG_RETURN_TIMESTAMPTZ(result);
5104 : }
5105 :
5106 : /* interval_trunc()
5107 : * Extract specified field from interval.
5108 : */
5109 : Datum
5110 12 : interval_trunc(PG_FUNCTION_ARGS)
5111 : {
5112 12 : text *units = PG_GETARG_TEXT_PP(0);
5113 12 : Interval *interval = PG_GETARG_INTERVAL_P(1);
5114 : Interval *result;
5115 : int type,
5116 : val;
5117 : char *lowunits;
5118 : struct pg_itm tt,
5119 12 : *tm = &tt;
5120 :
5121 12 : result = palloc_object(Interval);
5122 :
5123 12 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5124 12 : VARSIZE_ANY_EXHDR(units),
5125 : false);
5126 :
5127 12 : type = DecodeUnits(0, lowunits, &val);
5128 :
5129 12 : if (type == UNITS)
5130 : {
5131 9 : if (INTERVAL_NOT_FINITE(interval))
5132 : {
5133 : /*
5134 : * Errors thrown here for invalid units should exactly match those
5135 : * below, else there will be unexpected discrepancies between
5136 : * finite- and infinite-input cases.
5137 : */
5138 9 : switch (val)
5139 : {
5140 6 : case DTK_MILLENNIUM:
5141 : case DTK_CENTURY:
5142 : case DTK_DECADE:
5143 : case DTK_YEAR:
5144 : case DTK_QUARTER:
5145 : case DTK_MONTH:
5146 : case DTK_DAY:
5147 : case DTK_HOUR:
5148 : case DTK_MINUTE:
5149 : case DTK_SECOND:
5150 : case DTK_MILLISEC:
5151 : case DTK_MICROSEC:
5152 6 : memcpy(result, interval, sizeof(Interval));
5153 6 : PG_RETURN_INTERVAL_P(result);
5154 : break;
5155 :
5156 3 : default:
5157 3 : ereport(ERROR,
5158 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5159 : errmsg("unit \"%s\" not supported for type %s",
5160 : lowunits, format_type_be(INTERVALOID)),
5161 : (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
5162 : result = NULL;
5163 : }
5164 : }
5165 :
5166 0 : interval2itm(*interval, tm);
5167 0 : switch (val)
5168 : {
5169 0 : case DTK_MILLENNIUM:
5170 : /* caution: C division may have negative remainder */
5171 0 : tm->tm_year = (tm->tm_year / 1000) * 1000;
5172 : pg_fallthrough;
5173 0 : case DTK_CENTURY:
5174 : /* caution: C division may have negative remainder */
5175 0 : tm->tm_year = (tm->tm_year / 100) * 100;
5176 : pg_fallthrough;
5177 0 : case DTK_DECADE:
5178 : /* caution: C division may have negative remainder */
5179 0 : tm->tm_year = (tm->tm_year / 10) * 10;
5180 : pg_fallthrough;
5181 0 : case DTK_YEAR:
5182 0 : tm->tm_mon = 0;
5183 : pg_fallthrough;
5184 0 : case DTK_QUARTER:
5185 0 : tm->tm_mon = 3 * (tm->tm_mon / 3);
5186 : pg_fallthrough;
5187 0 : case DTK_MONTH:
5188 0 : tm->tm_mday = 0;
5189 : pg_fallthrough;
5190 0 : case DTK_DAY:
5191 0 : tm->tm_hour = 0;
5192 : pg_fallthrough;
5193 0 : case DTK_HOUR:
5194 0 : tm->tm_min = 0;
5195 : pg_fallthrough;
5196 0 : case DTK_MINUTE:
5197 0 : tm->tm_sec = 0;
5198 : pg_fallthrough;
5199 0 : case DTK_SECOND:
5200 0 : tm->tm_usec = 0;
5201 0 : break;
5202 0 : case DTK_MILLISEC:
5203 0 : tm->tm_usec = (tm->tm_usec / 1000) * 1000;
5204 0 : break;
5205 0 : case DTK_MICROSEC:
5206 0 : break;
5207 :
5208 0 : default:
5209 0 : ereport(ERROR,
5210 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5211 : errmsg("unit \"%s\" not supported for type %s",
5212 : lowunits, format_type_be(INTERVALOID)),
5213 : (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
5214 : }
5215 :
5216 0 : if (itm2interval(tm, result) != 0)
5217 0 : ereport(ERROR,
5218 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5219 : errmsg("interval out of range")));
5220 : }
5221 : else
5222 : {
5223 3 : ereport(ERROR,
5224 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5225 : errmsg("unit \"%s\" not recognized for type %s",
5226 : lowunits, format_type_be(INTERVALOID))));
5227 : }
5228 :
5229 0 : PG_RETURN_INTERVAL_P(result);
5230 : }
5231 :
5232 : /* isoweek2j()
5233 : *
5234 : * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
5235 : * Julian days are used to convert between ISO week dates and Gregorian dates.
5236 : *
5237 : * XXX: This function has integer overflow hazards, but restructuring it to
5238 : * work with the soft-error handling that its callers do is likely more
5239 : * trouble than it's worth.
5240 : */
5241 : int
5242 795 : isoweek2j(int year, int week)
5243 : {
5244 : int day0,
5245 : day4;
5246 :
5247 : /* fourth day of current year */
5248 795 : day4 = date2j(year, 1, 4);
5249 :
5250 : /* day0 == offset to first day of week (Monday) */
5251 795 : day0 = j2day(day4 - 1);
5252 :
5253 795 : return ((week - 1) * 7) + (day4 - day0);
5254 : }
5255 :
5256 : /* isoweek2date()
5257 : * Convert ISO week of year number to date.
5258 : * The year field must be specified with the ISO year!
5259 : * karel 2000/08/07
5260 : */
5261 : void
5262 18 : isoweek2date(int woy, int *year, int *mon, int *mday)
5263 : {
5264 18 : j2date(isoweek2j(*year, woy), year, mon, mday);
5265 18 : }
5266 :
5267 : /* isoweekdate2date()
5268 : *
5269 : * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
5270 : * Gregorian day of week sent so weekday strings can be supplied.
5271 : * Populates year, mon, and mday with the correct Gregorian values.
5272 : * year must be passed in as the ISO year.
5273 : */
5274 : void
5275 12 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
5276 : {
5277 : int jday;
5278 :
5279 12 : jday = isoweek2j(*year, isoweek);
5280 : /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
5281 12 : if (wday > 1)
5282 0 : jday += wday - 2;
5283 : else
5284 12 : jday += 6;
5285 12 : j2date(jday, year, mon, mday);
5286 12 : }
5287 :
5288 : /* date2isoweek()
5289 : *
5290 : * Returns ISO week number of year.
5291 : */
5292 : int
5293 1212 : date2isoweek(int year, int mon, int mday)
5294 : {
5295 : int day0,
5296 : day4,
5297 : dayn,
5298 : week;
5299 :
5300 : /* current day */
5301 1212 : dayn = date2j(year, mon, mday);
5302 :
5303 : /* fourth day of current year */
5304 1212 : day4 = date2j(year, 1, 4);
5305 :
5306 : /* day0 == offset to first day of week (Monday) */
5307 1212 : day0 = j2day(day4 - 1);
5308 :
5309 : /*
5310 : * We need the first week containing a Thursday, otherwise this day falls
5311 : * into the previous year for purposes of counting weeks
5312 : */
5313 1212 : if (dayn < day4 - day0)
5314 : {
5315 18 : day4 = date2j(year - 1, 1, 4);
5316 :
5317 : /* day0 == offset to first day of week (Monday) */
5318 18 : day0 = j2day(day4 - 1);
5319 : }
5320 :
5321 1212 : week = (dayn - (day4 - day0)) / 7 + 1;
5322 :
5323 : /*
5324 : * Sometimes the last few days in a year will fall into the first week of
5325 : * the next year, so check for this.
5326 : */
5327 1212 : if (week >= 52)
5328 : {
5329 135 : day4 = date2j(year + 1, 1, 4);
5330 :
5331 : /* day0 == offset to first day of week (Monday) */
5332 135 : day0 = j2day(day4 - 1);
5333 :
5334 135 : if (dayn >= day4 - day0)
5335 81 : week = (dayn - (day4 - day0)) / 7 + 1;
5336 : }
5337 :
5338 1212 : return week;
5339 : }
5340 :
5341 :
5342 : /* date2isoyear()
5343 : *
5344 : * Returns ISO 8601 year number.
5345 : * Note: zero or negative results follow the year-zero-exists convention.
5346 : */
5347 : int
5348 7293 : date2isoyear(int year, int mon, int mday)
5349 : {
5350 : int day0,
5351 : day4,
5352 : dayn,
5353 : week;
5354 :
5355 : /* current day */
5356 7293 : dayn = date2j(year, mon, mday);
5357 :
5358 : /* fourth day of current year */
5359 7293 : day4 = date2j(year, 1, 4);
5360 :
5361 : /* day0 == offset to first day of week (Monday) */
5362 7293 : day0 = j2day(day4 - 1);
5363 :
5364 : /*
5365 : * We need the first week containing a Thursday, otherwise this day falls
5366 : * into the previous year for purposes of counting weeks
5367 : */
5368 7293 : if (dayn < day4 - day0)
5369 : {
5370 114 : day4 = date2j(year - 1, 1, 4);
5371 :
5372 : /* day0 == offset to first day of week (Monday) */
5373 114 : day0 = j2day(day4 - 1);
5374 :
5375 114 : year--;
5376 : }
5377 :
5378 7293 : week = (dayn - (day4 - day0)) / 7 + 1;
5379 :
5380 : /*
5381 : * Sometimes the last few days in a year will fall into the first week of
5382 : * the next year, so check for this.
5383 : */
5384 7293 : if (week >= 52)
5385 : {
5386 855 : day4 = date2j(year + 1, 1, 4);
5387 :
5388 : /* day0 == offset to first day of week (Monday) */
5389 855 : day0 = j2day(day4 - 1);
5390 :
5391 855 : if (dayn >= day4 - day0)
5392 513 : year++;
5393 : }
5394 :
5395 7293 : return year;
5396 : }
5397 :
5398 :
5399 : /* date2isoyearday()
5400 : *
5401 : * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
5402 : * Possible return values are 1 through 371 (364 in non-leap years).
5403 : */
5404 : int
5405 762 : date2isoyearday(int year, int mon, int mday)
5406 : {
5407 762 : return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
5408 : }
5409 :
5410 : /*
5411 : * NonFiniteTimestampTzPart
5412 : *
5413 : * Used by timestamp_part and timestamptz_part when extracting from infinite
5414 : * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
5415 : * otherwise returns zero (which should be taken as meaning to return NULL).
5416 : *
5417 : * Errors thrown here for invalid units should exactly match those that
5418 : * would be thrown in the calling functions, else there will be unexpected
5419 : * discrepancies between finite- and infinite-input cases.
5420 : */
5421 : static float8
5422 306 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
5423 : bool isNegative, bool isTz)
5424 : {
5425 306 : if ((type != UNITS) && (type != RESERV))
5426 0 : ereport(ERROR,
5427 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5428 : errmsg("unit \"%s\" not recognized for type %s",
5429 : lowunits,
5430 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5431 :
5432 306 : switch (unit)
5433 : {
5434 : /* Oscillating units */
5435 198 : case DTK_MICROSEC:
5436 : case DTK_MILLISEC:
5437 : case DTK_SECOND:
5438 : case DTK_MINUTE:
5439 : case DTK_HOUR:
5440 : case DTK_DAY:
5441 : case DTK_MONTH:
5442 : case DTK_QUARTER:
5443 : case DTK_WEEK:
5444 : case DTK_DOW:
5445 : case DTK_ISODOW:
5446 : case DTK_DOY:
5447 : case DTK_TZ:
5448 : case DTK_TZ_MINUTE:
5449 : case DTK_TZ_HOUR:
5450 198 : return 0.0;
5451 :
5452 : /* Monotonically-increasing units */
5453 108 : case DTK_YEAR:
5454 : case DTK_DECADE:
5455 : case DTK_CENTURY:
5456 : case DTK_MILLENNIUM:
5457 : case DTK_JULIAN:
5458 : case DTK_ISOYEAR:
5459 : case DTK_EPOCH:
5460 108 : if (isNegative)
5461 54 : return -get_float8_infinity();
5462 : else
5463 54 : return get_float8_infinity();
5464 :
5465 0 : default:
5466 0 : ereport(ERROR,
5467 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5468 : errmsg("unit \"%s\" not supported for type %s",
5469 : lowunits,
5470 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5471 : return 0.0; /* keep compiler quiet */
5472 : }
5473 : }
5474 :
5475 : /* timestamp_part() and extract_timestamp()
5476 : * Extract specified field from timestamp.
5477 : */
5478 : static Datum
5479 5361 : timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5480 : {
5481 5361 : text *units = PG_GETARG_TEXT_PP(0);
5482 5361 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
5483 : int64 intresult;
5484 : Timestamp epoch;
5485 : int type,
5486 : val;
5487 : char *lowunits;
5488 : fsec_t fsec;
5489 : struct pg_tm tt,
5490 5361 : *tm = &tt;
5491 :
5492 5361 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5493 5361 : VARSIZE_ANY_EXHDR(units),
5494 : false);
5495 :
5496 5361 : type = DecodeUnits(0, lowunits, &val);
5497 5361 : if (type == UNKNOWN_FIELD)
5498 1857 : type = DecodeSpecial(0, lowunits, &val);
5499 :
5500 5361 : if (TIMESTAMP_NOT_FINITE(timestamp))
5501 : {
5502 144 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5503 : TIMESTAMP_IS_NOBEGIN(timestamp),
5504 : false);
5505 :
5506 144 : if (r != 0.0)
5507 : {
5508 54 : if (retnumeric)
5509 : {
5510 12 : if (r < 0)
5511 6 : return DirectFunctionCall3(numeric_in,
5512 : CStringGetDatum("-Infinity"),
5513 : ObjectIdGetDatum(InvalidOid),
5514 : Int32GetDatum(-1));
5515 6 : else if (r > 0)
5516 6 : return DirectFunctionCall3(numeric_in,
5517 : CStringGetDatum("Infinity"),
5518 : ObjectIdGetDatum(InvalidOid),
5519 : Int32GetDatum(-1));
5520 : }
5521 : else
5522 42 : PG_RETURN_FLOAT8(r);
5523 : }
5524 : else
5525 90 : PG_RETURN_NULL();
5526 : }
5527 :
5528 5217 : if (type == UNITS)
5529 : {
5530 4782 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
5531 0 : ereport(ERROR,
5532 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5533 : errmsg("timestamp out of range")));
5534 :
5535 4782 : switch (val)
5536 : {
5537 378 : case DTK_MICROSEC:
5538 378 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5539 378 : break;
5540 :
5541 378 : case DTK_MILLISEC:
5542 378 : if (retnumeric)
5543 : /*---
5544 : * tm->tm_sec * 1000 + fsec / 1000
5545 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5546 : */
5547 189 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5548 : else
5549 189 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5550 : break;
5551 :
5552 378 : case DTK_SECOND:
5553 378 : if (retnumeric)
5554 : /*---
5555 : * tm->tm_sec + fsec / 1'000'000
5556 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5557 : */
5558 189 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5559 : else
5560 189 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5561 : break;
5562 :
5563 189 : case DTK_MINUTE:
5564 189 : intresult = tm->tm_min;
5565 189 : break;
5566 :
5567 189 : case DTK_HOUR:
5568 189 : intresult = tm->tm_hour;
5569 189 : break;
5570 :
5571 237 : case DTK_DAY:
5572 237 : intresult = tm->tm_mday;
5573 237 : break;
5574 :
5575 237 : case DTK_MONTH:
5576 237 : intresult = tm->tm_mon;
5577 237 : break;
5578 :
5579 237 : case DTK_QUARTER:
5580 237 : intresult = (tm->tm_mon - 1) / 3 + 1;
5581 237 : break;
5582 :
5583 237 : case DTK_WEEK:
5584 237 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5585 237 : break;
5586 :
5587 237 : case DTK_YEAR:
5588 237 : if (tm->tm_year > 0)
5589 231 : intresult = tm->tm_year;
5590 : else
5591 : /* there is no year 0, just 1 BC and 1 AD */
5592 6 : intresult = tm->tm_year - 1;
5593 237 : break;
5594 :
5595 237 : case DTK_DECADE:
5596 :
5597 : /*
5598 : * what is a decade wrt dates? let us assume that decade 199
5599 : * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
5600 : * is 11 BC thru 2 BC...
5601 : */
5602 237 : if (tm->tm_year >= 0)
5603 231 : intresult = tm->tm_year / 10;
5604 : else
5605 6 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5606 237 : break;
5607 :
5608 237 : case DTK_CENTURY:
5609 :
5610 : /* ----
5611 : * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
5612 : * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
5613 : * there is no number 0 century.
5614 : * ----
5615 : */
5616 237 : if (tm->tm_year > 0)
5617 231 : intresult = (tm->tm_year + 99) / 100;
5618 : else
5619 : /* caution: C division may have negative remainder */
5620 6 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5621 237 : break;
5622 :
5623 237 : case DTK_MILLENNIUM:
5624 : /* see comments above. */
5625 237 : if (tm->tm_year > 0)
5626 231 : intresult = (tm->tm_year + 999) / 1000;
5627 : else
5628 6 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5629 237 : break;
5630 :
5631 426 : case DTK_JULIAN:
5632 426 : if (retnumeric)
5633 189 : PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5634 : numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
5635 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5636 : NULL),
5637 : NULL));
5638 : else
5639 237 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5640 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5641 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5642 : break;
5643 :
5644 237 : case DTK_ISOYEAR:
5645 237 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5646 : /* Adjust BC years */
5647 237 : if (intresult <= 0)
5648 6 : intresult -= 1;
5649 237 : break;
5650 :
5651 474 : case DTK_DOW:
5652 : case DTK_ISODOW:
5653 474 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5654 474 : if (val == DTK_ISODOW && intresult == 0)
5655 15 : intresult = 7;
5656 474 : break;
5657 :
5658 237 : case DTK_DOY:
5659 237 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5660 237 : - date2j(tm->tm_year, 1, 1) + 1);
5661 237 : break;
5662 :
5663 0 : case DTK_TZ:
5664 : case DTK_TZ_MINUTE:
5665 : case DTK_TZ_HOUR:
5666 : default:
5667 0 : ereport(ERROR,
5668 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5669 : errmsg("unit \"%s\" not supported for type %s",
5670 : lowunits, format_type_be(TIMESTAMPOID))));
5671 : intresult = 0;
5672 : }
5673 : }
5674 435 : else if (type == RESERV)
5675 : {
5676 435 : switch (val)
5677 : {
5678 435 : case DTK_EPOCH:
5679 435 : epoch = SetEpochTimestamp();
5680 : /* (timestamp - epoch) / 1000000 */
5681 435 : if (retnumeric)
5682 : {
5683 : Numeric result;
5684 :
5685 195 : if (timestamp < (PG_INT64_MAX + epoch))
5686 192 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5687 : else
5688 : {
5689 3 : result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
5690 : int64_to_numeric(epoch),
5691 : NULL),
5692 : int64_to_numeric(1000000),
5693 : NULL);
5694 3 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5695 : NumericGetDatum(result),
5696 : Int32GetDatum(6)));
5697 : }
5698 195 : PG_RETURN_NUMERIC(result);
5699 : }
5700 : else
5701 : {
5702 : float8 result;
5703 :
5704 : /* try to avoid precision loss in subtraction */
5705 240 : if (timestamp < (PG_INT64_MAX + epoch))
5706 237 : result = (timestamp - epoch) / 1000000.0;
5707 : else
5708 3 : result = ((float8) timestamp - epoch) / 1000000.0;
5709 240 : PG_RETURN_FLOAT8(result);
5710 : }
5711 : break;
5712 :
5713 0 : default:
5714 0 : ereport(ERROR,
5715 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5716 : errmsg("unit \"%s\" not supported for type %s",
5717 : lowunits, format_type_be(TIMESTAMPOID))));
5718 : intresult = 0;
5719 : }
5720 : }
5721 : else
5722 : {
5723 0 : ereport(ERROR,
5724 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5725 : errmsg("unit \"%s\" not recognized for type %s",
5726 : lowunits, format_type_be(TIMESTAMPOID))));
5727 : intresult = 0;
5728 : }
5729 :
5730 3600 : if (retnumeric)
5731 189 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
5732 : else
5733 3411 : PG_RETURN_FLOAT8(intresult);
5734 : }
5735 :
5736 : Datum
5737 4380 : timestamp_part(PG_FUNCTION_ARGS)
5738 : {
5739 4380 : return timestamp_part_common(fcinfo, false);
5740 : }
5741 :
5742 : Datum
5743 981 : extract_timestamp(PG_FUNCTION_ARGS)
5744 : {
5745 981 : return timestamp_part_common(fcinfo, true);
5746 : }
5747 :
5748 : /* timestamptz_part() and extract_timestamptz()
5749 : * Extract specified field from timestamp with time zone.
5750 : */
5751 : static Datum
5752 18736 : timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5753 : {
5754 18736 : text *units = PG_GETARG_TEXT_PP(0);
5755 18736 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5756 : int64 intresult;
5757 : Timestamp epoch;
5758 : int tz;
5759 : int type,
5760 : val;
5761 : char *lowunits;
5762 : fsec_t fsec;
5763 : struct pg_tm tt,
5764 18736 : *tm = &tt;
5765 :
5766 18736 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5767 18736 : VARSIZE_ANY_EXHDR(units),
5768 : false);
5769 :
5770 18736 : type = DecodeUnits(0, lowunits, &val);
5771 18736 : if (type == UNKNOWN_FIELD)
5772 14962 : type = DecodeSpecial(0, lowunits, &val);
5773 :
5774 18736 : if (TIMESTAMP_NOT_FINITE(timestamp))
5775 : {
5776 162 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5777 : TIMESTAMP_IS_NOBEGIN(timestamp),
5778 : true);
5779 :
5780 162 : if (r != 0.0)
5781 : {
5782 54 : if (retnumeric)
5783 : {
5784 12 : if (r < 0)
5785 6 : return DirectFunctionCall3(numeric_in,
5786 : CStringGetDatum("-Infinity"),
5787 : ObjectIdGetDatum(InvalidOid),
5788 : Int32GetDatum(-1));
5789 6 : else if (r > 0)
5790 6 : return DirectFunctionCall3(numeric_in,
5791 : CStringGetDatum("Infinity"),
5792 : ObjectIdGetDatum(InvalidOid),
5793 : Int32GetDatum(-1));
5794 : }
5795 : else
5796 42 : PG_RETURN_FLOAT8(r);
5797 : }
5798 : else
5799 108 : PG_RETURN_NULL();
5800 : }
5801 :
5802 18574 : if (type == UNITS)
5803 : {
5804 4842 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5805 0 : ereport(ERROR,
5806 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5807 : errmsg("timestamp out of range")));
5808 :
5809 4842 : switch (val)
5810 : {
5811 192 : case DTK_TZ:
5812 192 : intresult = -tz;
5813 192 : break;
5814 :
5815 192 : case DTK_TZ_MINUTE:
5816 192 : intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
5817 192 : break;
5818 :
5819 192 : case DTK_TZ_HOUR:
5820 192 : intresult = -tz / SECS_PER_HOUR;
5821 192 : break;
5822 :
5823 384 : case DTK_MICROSEC:
5824 384 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5825 384 : break;
5826 :
5827 384 : case DTK_MILLISEC:
5828 384 : if (retnumeric)
5829 : /*---
5830 : * tm->tm_sec * 1000 + fsec / 1000
5831 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5832 : */
5833 192 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5834 : else
5835 192 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5836 : break;
5837 :
5838 384 : case DTK_SECOND:
5839 384 : if (retnumeric)
5840 : /*---
5841 : * tm->tm_sec + fsec / 1'000'000
5842 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5843 : */
5844 192 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5845 : else
5846 192 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5847 : break;
5848 :
5849 192 : case DTK_MINUTE:
5850 192 : intresult = tm->tm_min;
5851 192 : break;
5852 :
5853 192 : case DTK_HOUR:
5854 192 : intresult = tm->tm_hour;
5855 192 : break;
5856 :
5857 192 : case DTK_DAY:
5858 192 : intresult = tm->tm_mday;
5859 192 : break;
5860 :
5861 192 : case DTK_MONTH:
5862 192 : intresult = tm->tm_mon;
5863 192 : break;
5864 :
5865 192 : case DTK_QUARTER:
5866 192 : intresult = (tm->tm_mon - 1) / 3 + 1;
5867 192 : break;
5868 :
5869 192 : case DTK_WEEK:
5870 192 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5871 192 : break;
5872 :
5873 204 : case DTK_YEAR:
5874 204 : if (tm->tm_year > 0)
5875 201 : intresult = tm->tm_year;
5876 : else
5877 : /* there is no year 0, just 1 BC and 1 AD */
5878 3 : intresult = tm->tm_year - 1;
5879 204 : break;
5880 :
5881 192 : case DTK_DECADE:
5882 : /* see comments in timestamp_part */
5883 192 : if (tm->tm_year > 0)
5884 189 : intresult = tm->tm_year / 10;
5885 : else
5886 3 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5887 192 : break;
5888 :
5889 192 : case DTK_CENTURY:
5890 : /* see comments in timestamp_part */
5891 192 : if (tm->tm_year > 0)
5892 189 : intresult = (tm->tm_year + 99) / 100;
5893 : else
5894 3 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5895 192 : break;
5896 :
5897 192 : case DTK_MILLENNIUM:
5898 : /* see comments in timestamp_part */
5899 192 : if (tm->tm_year > 0)
5900 189 : intresult = (tm->tm_year + 999) / 1000;
5901 : else
5902 3 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5903 192 : break;
5904 :
5905 384 : case DTK_JULIAN:
5906 384 : if (retnumeric)
5907 192 : PG_RETURN_NUMERIC(numeric_add_safe(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5908 : numeric_div_safe(int64_to_numeric(((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) * INT64CONST(1000000) + fsec),
5909 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5910 : NULL),
5911 : NULL));
5912 : else
5913 192 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5914 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5915 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5916 : break;
5917 :
5918 192 : case DTK_ISOYEAR:
5919 192 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5920 : /* Adjust BC years */
5921 192 : if (intresult <= 0)
5922 3 : intresult -= 1;
5923 192 : break;
5924 :
5925 414 : case DTK_DOW:
5926 : case DTK_ISODOW:
5927 414 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5928 414 : if (val == DTK_ISODOW && intresult == 0)
5929 9 : intresult = 7;
5930 414 : break;
5931 :
5932 192 : case DTK_DOY:
5933 192 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5934 192 : - date2j(tm->tm_year, 1, 1) + 1);
5935 192 : break;
5936 :
5937 0 : default:
5938 0 : ereport(ERROR,
5939 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5940 : errmsg("unit \"%s\" not supported for type %s",
5941 : lowunits, format_type_be(TIMESTAMPTZOID))));
5942 : intresult = 0;
5943 : }
5944 : }
5945 13732 : else if (type == RESERV)
5946 : {
5947 13732 : switch (val)
5948 : {
5949 13732 : case DTK_EPOCH:
5950 13732 : epoch = SetEpochTimestamp();
5951 : /* (timestamp - epoch) / 1000000 */
5952 13732 : if (retnumeric)
5953 : {
5954 : Numeric result;
5955 :
5956 13537 : if (timestamp < (PG_INT64_MAX + epoch))
5957 13534 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5958 : else
5959 : {
5960 3 : result = numeric_div_safe(numeric_sub_safe(int64_to_numeric(timestamp),
5961 : int64_to_numeric(epoch),
5962 : NULL),
5963 : int64_to_numeric(1000000),
5964 : NULL);
5965 3 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5966 : NumericGetDatum(result),
5967 : Int32GetDatum(6)));
5968 : }
5969 13537 : PG_RETURN_NUMERIC(result);
5970 : }
5971 : else
5972 : {
5973 : float8 result;
5974 :
5975 : /* try to avoid precision loss in subtraction */
5976 195 : if (timestamp < (PG_INT64_MAX + epoch))
5977 192 : result = (timestamp - epoch) / 1000000.0;
5978 : else
5979 3 : result = ((float8) timestamp - epoch) / 1000000.0;
5980 195 : PG_RETURN_FLOAT8(result);
5981 : }
5982 : break;
5983 :
5984 0 : default:
5985 0 : ereport(ERROR,
5986 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5987 : errmsg("unit \"%s\" not supported for type %s",
5988 : lowunits, format_type_be(TIMESTAMPTZOID))));
5989 : intresult = 0;
5990 : }
5991 : }
5992 : else
5993 : {
5994 0 : ereport(ERROR,
5995 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5996 : errmsg("unit \"%s\" not recognized for type %s",
5997 : lowunits, format_type_be(TIMESTAMPTZOID))));
5998 :
5999 : intresult = 0;
6000 : }
6001 :
6002 3690 : if (retnumeric)
6003 234 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
6004 : else
6005 3456 : PG_RETURN_FLOAT8(intresult);
6006 : }
6007 :
6008 : Datum
6009 4359 : timestamptz_part(PG_FUNCTION_ARGS)
6010 : {
6011 4359 : return timestamptz_part_common(fcinfo, false);
6012 : }
6013 :
6014 : Datum
6015 14377 : extract_timestamptz(PG_FUNCTION_ARGS)
6016 : {
6017 14377 : return timestamptz_part_common(fcinfo, true);
6018 : }
6019 :
6020 : /*
6021 : * NonFiniteIntervalPart
6022 : *
6023 : * Used by interval_part when extracting from infinite interval. Returns
6024 : * +/-Infinity if that is the appropriate result, otherwise returns zero
6025 : * (which should be taken as meaning to return NULL).
6026 : *
6027 : * Errors thrown here for invalid units should exactly match those that
6028 : * would be thrown in the calling functions, else there will be unexpected
6029 : * discrepancies between finite- and infinite-input cases.
6030 : */
6031 : static float8
6032 192 : NonFiniteIntervalPart(int type, int unit, char *lowunits, bool isNegative)
6033 : {
6034 192 : if ((type != UNITS) && (type != RESERV))
6035 0 : ereport(ERROR,
6036 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6037 : errmsg("unit \"%s\" not recognized for type %s",
6038 : lowunits, format_type_be(INTERVALOID))));
6039 :
6040 192 : switch (unit)
6041 : {
6042 : /* Oscillating units */
6043 102 : case DTK_MICROSEC:
6044 : case DTK_MILLISEC:
6045 : case DTK_SECOND:
6046 : case DTK_MINUTE:
6047 : case DTK_WEEK:
6048 : case DTK_MONTH:
6049 : case DTK_QUARTER:
6050 102 : return 0.0;
6051 :
6052 : /* Monotonically-increasing units */
6053 90 : case DTK_HOUR:
6054 : case DTK_DAY:
6055 : case DTK_YEAR:
6056 : case DTK_DECADE:
6057 : case DTK_CENTURY:
6058 : case DTK_MILLENNIUM:
6059 : case DTK_EPOCH:
6060 90 : if (isNegative)
6061 45 : return -get_float8_infinity();
6062 : else
6063 45 : return get_float8_infinity();
6064 :
6065 0 : default:
6066 0 : ereport(ERROR,
6067 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6068 : errmsg("unit \"%s\" not supported for type %s",
6069 : lowunits, format_type_be(INTERVALOID))));
6070 : return 0.0; /* keep compiler quiet */
6071 : }
6072 : }
6073 :
6074 : /* interval_part() and extract_interval()
6075 : * Extract specified field from interval.
6076 : */
6077 : static Datum
6078 1188 : interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
6079 : {
6080 1188 : text *units = PG_GETARG_TEXT_PP(0);
6081 1188 : Interval *interval = PG_GETARG_INTERVAL_P(1);
6082 : int64 intresult;
6083 : int type,
6084 : val;
6085 : char *lowunits;
6086 : struct pg_itm tt,
6087 1188 : *tm = &tt;
6088 :
6089 1188 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
6090 1188 : VARSIZE_ANY_EXHDR(units),
6091 : false);
6092 :
6093 1188 : type = DecodeUnits(0, lowunits, &val);
6094 1188 : if (type == UNKNOWN_FIELD)
6095 117 : type = DecodeSpecial(0, lowunits, &val);
6096 :
6097 1188 : if (INTERVAL_NOT_FINITE(interval))
6098 : {
6099 192 : double r = NonFiniteIntervalPart(type, val, lowunits,
6100 192 : INTERVAL_IS_NOBEGIN(interval));
6101 :
6102 192 : if (r != 0.0)
6103 : {
6104 90 : if (retnumeric)
6105 : {
6106 84 : if (r < 0)
6107 42 : return DirectFunctionCall3(numeric_in,
6108 : CStringGetDatum("-Infinity"),
6109 : ObjectIdGetDatum(InvalidOid),
6110 : Int32GetDatum(-1));
6111 42 : else if (r > 0)
6112 42 : return DirectFunctionCall3(numeric_in,
6113 : CStringGetDatum("Infinity"),
6114 : ObjectIdGetDatum(InvalidOid),
6115 : Int32GetDatum(-1));
6116 : }
6117 : else
6118 6 : PG_RETURN_FLOAT8(r);
6119 : }
6120 : else
6121 102 : PG_RETURN_NULL();
6122 : }
6123 :
6124 996 : if (type == UNITS)
6125 : {
6126 897 : interval2itm(*interval, tm);
6127 897 : switch (val)
6128 : {
6129 90 : case DTK_MICROSEC:
6130 90 : intresult = tm->tm_sec * INT64CONST(1000000) + tm->tm_usec;
6131 90 : break;
6132 :
6133 90 : case DTK_MILLISEC:
6134 90 : if (retnumeric)
6135 : /*---
6136 : * tm->tm_sec * 1000 + fsec / 1000
6137 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
6138 : */
6139 60 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 3));
6140 : else
6141 30 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + tm->tm_usec / 1000.0);
6142 : break;
6143 :
6144 90 : case DTK_SECOND:
6145 90 : if (retnumeric)
6146 : /*---
6147 : * tm->tm_sec + fsec / 1'000'000
6148 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
6149 : */
6150 60 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 6));
6151 : else
6152 30 : PG_RETURN_FLOAT8(tm->tm_sec + tm->tm_usec / 1000000.0);
6153 : break;
6154 :
6155 60 : case DTK_MINUTE:
6156 60 : intresult = tm->tm_min;
6157 60 : break;
6158 :
6159 60 : case DTK_HOUR:
6160 60 : intresult = tm->tm_hour;
6161 60 : break;
6162 :
6163 60 : case DTK_DAY:
6164 60 : intresult = tm->tm_mday;
6165 60 : break;
6166 :
6167 60 : case DTK_WEEK:
6168 60 : intresult = tm->tm_mday / 7;
6169 60 : break;
6170 :
6171 60 : case DTK_MONTH:
6172 60 : intresult = tm->tm_mon;
6173 60 : break;
6174 :
6175 60 : case DTK_QUARTER:
6176 :
6177 : /*
6178 : * We want to maintain the rule that a field extracted from a
6179 : * negative interval is the negative of the field's value for
6180 : * the sign-reversed interval. The broken-down tm_year and
6181 : * tm_mon aren't very helpful for that, so work from
6182 : * interval->month.
6183 : */
6184 60 : if (interval->month >= 0)
6185 45 : intresult = (tm->tm_mon / 3) + 1;
6186 : else
6187 15 : intresult = -(((-interval->month % MONTHS_PER_YEAR) / 3) + 1);
6188 60 : break;
6189 :
6190 60 : case DTK_YEAR:
6191 60 : intresult = tm->tm_year;
6192 60 : break;
6193 :
6194 72 : case DTK_DECADE:
6195 : /* caution: C division may have negative remainder */
6196 72 : intresult = tm->tm_year / 10;
6197 72 : break;
6198 :
6199 72 : case DTK_CENTURY:
6200 : /* caution: C division may have negative remainder */
6201 72 : intresult = tm->tm_year / 100;
6202 72 : break;
6203 :
6204 60 : case DTK_MILLENNIUM:
6205 : /* caution: C division may have negative remainder */
6206 60 : intresult = tm->tm_year / 1000;
6207 60 : break;
6208 :
6209 3 : default:
6210 3 : ereport(ERROR,
6211 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6212 : errmsg("unit \"%s\" not supported for type %s",
6213 : lowunits, format_type_be(INTERVALOID))));
6214 : intresult = 0;
6215 : }
6216 : }
6217 99 : else if (type == RESERV && val == DTK_EPOCH)
6218 : {
6219 96 : if (retnumeric)
6220 : {
6221 : Numeric result;
6222 : int64 secs_from_day_month;
6223 : int64 val;
6224 :
6225 : /*
6226 : * To do this calculation in integer arithmetic even though
6227 : * DAYS_PER_YEAR is fractional, multiply everything by 4 and then
6228 : * divide by 4 again at the end. This relies on DAYS_PER_YEAR
6229 : * being a multiple of 0.25 and on SECS_PER_DAY being a multiple
6230 : * of 4.
6231 : */
6232 66 : secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) +
6233 66 : (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) +
6234 66 : (int64) 4 * interval->day) * (SECS_PER_DAY / 4);
6235 :
6236 : /*---
6237 : * result = secs_from_day_month + interval->time / 1'000'000
6238 : * = (secs_from_day_month * 1'000'000 + interval->time) / 1'000'000
6239 : */
6240 :
6241 : /*
6242 : * Try the computation inside int64; if it overflows, do it in
6243 : * numeric (slower). This overflow happens around 10^9 days, so
6244 : * not common in practice.
6245 : */
6246 66 : if (!pg_mul_s64_overflow(secs_from_day_month, 1000000, &val) &&
6247 63 : !pg_add_s64_overflow(val, interval->time, &val))
6248 63 : result = int64_div_fast_to_numeric(val, 6);
6249 : else
6250 : result =
6251 3 : numeric_add_safe(int64_div_fast_to_numeric(interval->time, 6),
6252 : int64_to_numeric(secs_from_day_month),
6253 : NULL);
6254 :
6255 66 : PG_RETURN_NUMERIC(result);
6256 : }
6257 : else
6258 : {
6259 : float8 result;
6260 :
6261 30 : result = interval->time / 1000000.0;
6262 30 : result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
6263 30 : result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
6264 30 : result += ((double) SECS_PER_DAY) * interval->day;
6265 :
6266 30 : PG_RETURN_FLOAT8(result);
6267 : }
6268 : }
6269 : else
6270 : {
6271 3 : ereport(ERROR,
6272 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6273 : errmsg("unit \"%s\" not recognized for type %s",
6274 : lowunits, format_type_be(INTERVALOID))));
6275 : intresult = 0;
6276 : }
6277 :
6278 714 : if (retnumeric)
6279 684 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
6280 : else
6281 30 : PG_RETURN_FLOAT8(intresult);
6282 : }
6283 :
6284 : Datum
6285 144 : interval_part(PG_FUNCTION_ARGS)
6286 : {
6287 144 : return interval_part_common(fcinfo, false);
6288 : }
6289 :
6290 : Datum
6291 1044 : extract_interval(PG_FUNCTION_ARGS)
6292 : {
6293 1044 : return interval_part_common(fcinfo, true);
6294 : }
6295 :
6296 :
6297 : /* timestamp_zone()
6298 : * Encode timestamp type with specified time zone.
6299 : * This function is just timestamp2timestamptz() except instead of
6300 : * shifting to the global timezone, we shift to the specified timezone.
6301 : * This is different from the other AT TIME ZONE cases because instead
6302 : * of shifting _to_ a new time zone, it sets the time to _be_ the
6303 : * specified timezone.
6304 : */
6305 : Datum
6306 84 : timestamp_zone(PG_FUNCTION_ARGS)
6307 : {
6308 84 : text *zone = PG_GETARG_TEXT_PP(0);
6309 84 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6310 : TimestampTz result;
6311 : int tz;
6312 : char tzname[TZ_STRLEN_MAX + 1];
6313 : int type,
6314 : val;
6315 : pg_tz *tzp;
6316 : struct pg_tm tm;
6317 : fsec_t fsec;
6318 :
6319 84 : if (TIMESTAMP_NOT_FINITE(timestamp))
6320 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6321 :
6322 : /*
6323 : * Look up the requested timezone.
6324 : */
6325 84 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6326 :
6327 84 : type = DecodeTimezoneName(tzname, &val, &tzp);
6328 :
6329 84 : if (type == TZNAME_FIXED_OFFSET)
6330 : {
6331 : /* fixed-offset abbreviation */
6332 0 : tz = val;
6333 0 : result = dt2local(timestamp, tz);
6334 : }
6335 84 : else if (type == TZNAME_DYNTZ)
6336 : {
6337 : /* dynamic-offset abbreviation, resolve using specified time */
6338 42 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6339 0 : ereport(ERROR,
6340 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6341 : errmsg("timestamp out of range")));
6342 42 : tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
6343 42 : result = dt2local(timestamp, tz);
6344 : }
6345 : else
6346 : {
6347 : /* full zone name, rotate to that zone */
6348 42 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6349 0 : ereport(ERROR,
6350 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6351 : errmsg("timestamp out of range")));
6352 42 : tz = DetermineTimeZoneOffset(&tm, tzp);
6353 42 : if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
6354 0 : ereport(ERROR,
6355 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6356 : errmsg("timestamp out of range")));
6357 : }
6358 :
6359 84 : if (!IS_VALID_TIMESTAMP(result))
6360 0 : ereport(ERROR,
6361 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6362 : errmsg("timestamp out of range")));
6363 :
6364 84 : PG_RETURN_TIMESTAMPTZ(result);
6365 : }
6366 :
6367 : /* timestamp_izone()
6368 : * Encode timestamp type with specified time interval as time zone.
6369 : */
6370 : Datum
6371 6 : timestamp_izone(PG_FUNCTION_ARGS)
6372 : {
6373 6 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6374 6 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6375 : TimestampTz result;
6376 : int tz;
6377 :
6378 6 : if (TIMESTAMP_NOT_FINITE(timestamp))
6379 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6380 :
6381 6 : if (INTERVAL_NOT_FINITE(zone))
6382 6 : ereport(ERROR,
6383 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6384 : errmsg("interval time zone \"%s\" must be finite",
6385 : DatumGetCString(DirectFunctionCall1(interval_out,
6386 : PointerGetDatum(zone))))));
6387 :
6388 0 : if (zone->month != 0 || zone->day != 0)
6389 0 : ereport(ERROR,
6390 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6391 : errmsg("interval time zone \"%s\" must not include months or days",
6392 : DatumGetCString(DirectFunctionCall1(interval_out,
6393 : PointerGetDatum(zone))))));
6394 :
6395 0 : tz = zone->time / USECS_PER_SEC;
6396 :
6397 0 : result = dt2local(timestamp, tz);
6398 :
6399 0 : if (!IS_VALID_TIMESTAMP(result))
6400 0 : ereport(ERROR,
6401 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6402 : errmsg("timestamp out of range")));
6403 :
6404 0 : PG_RETURN_TIMESTAMPTZ(result);
6405 : } /* timestamp_izone() */
6406 :
6407 : /* TimestampTimestampTzRequiresRewrite()
6408 : *
6409 : * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
6410 : * timestamptz_timestamp to be no-ops, where the return value has the same
6411 : * bits as the argument. Since project convention is to assume a GUC changes
6412 : * no more often than STABLE functions change, the answer is valid that long.
6413 : */
6414 : bool
6415 9 : TimestampTimestampTzRequiresRewrite(void)
6416 : {
6417 : long offset;
6418 :
6419 9 : if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
6420 6 : return false;
6421 3 : return true;
6422 : }
6423 :
6424 : /* timestamp_timestamptz()
6425 : * Convert local timestamp to timestamp at GMT
6426 : */
6427 : Datum
6428 111 : timestamp_timestamptz(PG_FUNCTION_ARGS)
6429 : {
6430 111 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
6431 :
6432 111 : PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
6433 : }
6434 :
6435 : /*
6436 : * Convert timestamp to timestamp with time zone.
6437 : *
6438 : * If the timestamp is finite but out of the valid range for timestamptz,
6439 : * error handling proceeds based on escontext.
6440 : *
6441 : * If escontext is NULL, we throw an out-of-range error (hard error).
6442 : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
6443 : * upper bound overflow, respectively, and record a soft error.
6444 : */
6445 : TimestampTz
6446 8160 : timestamp2timestamptz_safe(Timestamp timestamp, Node *escontext)
6447 : {
6448 : TimestampTz result;
6449 : struct pg_tm tt,
6450 8160 : *tm = &tt;
6451 : fsec_t fsec;
6452 : int tz;
6453 :
6454 8160 : if (TIMESTAMP_NOT_FINITE(timestamp))
6455 17 : return timestamp;
6456 :
6457 : /* timestamp2tm should not fail on valid timestamps, but cope */
6458 8143 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
6459 : {
6460 8143 : tz = DetermineTimeZoneOffset(tm, session_timezone);
6461 :
6462 8143 : result = dt2local(timestamp, -tz);
6463 :
6464 8143 : if (IS_VALID_TIMESTAMP(result))
6465 8137 : return result;
6466 : }
6467 :
6468 6 : if (timestamp < 0)
6469 6 : TIMESTAMP_NOBEGIN(result);
6470 : else
6471 0 : TIMESTAMP_NOEND(result);
6472 :
6473 6 : ereturn(escontext, result,
6474 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6475 : errmsg("timestamp out of range")));
6476 : }
6477 :
6478 : /*
6479 : * Promote timestamp to timestamptz, throwing error for overflow.
6480 : */
6481 : static TimestampTz
6482 117 : timestamp2timestamptz(Timestamp timestamp)
6483 : {
6484 117 : return timestamp2timestamptz_safe(timestamp, NULL);
6485 : }
6486 :
6487 : /* timestamptz_timestamp()
6488 : * Convert timestamp at GMT to local timestamp
6489 : */
6490 : Datum
6491 31086 : timestamptz_timestamp(PG_FUNCTION_ARGS)
6492 : {
6493 31086 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
6494 :
6495 31086 : PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
6496 : }
6497 :
6498 : /*
6499 : * Convert timestamptz to timestamp, throwing error for overflow.
6500 : */
6501 : static Timestamp
6502 31119 : timestamptz2timestamp(TimestampTz timestamp)
6503 : {
6504 31119 : return timestamptz2timestamp_safe(timestamp, NULL);
6505 : }
6506 :
6507 : /*
6508 : * Convert timestamp with time zone to timestamp.
6509 : *
6510 : * If the timestamptz is finite but out of the valid range for timestamp,
6511 : * error handling proceeds based on escontext.
6512 : *
6513 : * If escontext is NULL, we throw an out-of-range error (hard error).
6514 : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
6515 : * upper bound overflow, respectively, and record a soft error.
6516 : */
6517 : Timestamp
6518 31139 : timestamptz2timestamp_safe(TimestampTz timestamp, Node *escontext)
6519 : {
6520 : Timestamp result;
6521 : struct pg_tm tt,
6522 31139 : *tm = &tt;
6523 : fsec_t fsec;
6524 : int tz;
6525 :
6526 31139 : if (TIMESTAMP_NOT_FINITE(timestamp))
6527 12 : result = timestamp;
6528 : else
6529 : {
6530 31127 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
6531 : {
6532 0 : if (timestamp < 0)
6533 0 : TIMESTAMP_NOBEGIN(result);
6534 : else
6535 0 : TIMESTAMP_NOEND(result);
6536 :
6537 0 : ereturn(escontext, result,
6538 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6539 : errmsg("timestamp out of range")));
6540 : }
6541 31127 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
6542 : {
6543 2 : if (timestamp < 0)
6544 2 : TIMESTAMP_NOBEGIN(result);
6545 : else
6546 0 : TIMESTAMP_NOEND(result);
6547 :
6548 2 : ereturn(escontext, result,
6549 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6550 : errmsg("timestamp out of range")));
6551 : }
6552 : }
6553 31137 : return result;
6554 : }
6555 :
6556 : /* timestamptz_zone()
6557 : * Evaluate timestamp with time zone type at the specified time zone.
6558 : * Returns a timestamp without time zone.
6559 : */
6560 : Datum
6561 117 : timestamptz_zone(PG_FUNCTION_ARGS)
6562 : {
6563 117 : text *zone = PG_GETARG_TEXT_PP(0);
6564 117 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6565 : Timestamp result;
6566 : int tz;
6567 : char tzname[TZ_STRLEN_MAX + 1];
6568 : int type,
6569 : val;
6570 : pg_tz *tzp;
6571 :
6572 117 : if (TIMESTAMP_NOT_FINITE(timestamp))
6573 12 : PG_RETURN_TIMESTAMP(timestamp);
6574 :
6575 : /*
6576 : * Look up the requested timezone.
6577 : */
6578 105 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6579 :
6580 105 : type = DecodeTimezoneName(tzname, &val, &tzp);
6581 :
6582 102 : if (type == TZNAME_FIXED_OFFSET)
6583 : {
6584 : /* fixed-offset abbreviation */
6585 24 : tz = -val;
6586 24 : result = dt2local(timestamp, tz);
6587 : }
6588 78 : else if (type == TZNAME_DYNTZ)
6589 : {
6590 : /* dynamic-offset abbreviation, resolve using specified time */
6591 : int isdst;
6592 :
6593 36 : tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
6594 36 : result = dt2local(timestamp, tz);
6595 : }
6596 : else
6597 : {
6598 : /* full zone name, rotate from that zone */
6599 : struct pg_tm tm;
6600 : fsec_t fsec;
6601 :
6602 42 : if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
6603 0 : ereport(ERROR,
6604 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6605 : errmsg("timestamp out of range")));
6606 42 : if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
6607 0 : ereport(ERROR,
6608 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6609 : errmsg("timestamp out of range")));
6610 : }
6611 :
6612 102 : if (!IS_VALID_TIMESTAMP(result))
6613 0 : ereport(ERROR,
6614 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6615 : errmsg("timestamp out of range")));
6616 :
6617 102 : PG_RETURN_TIMESTAMP(result);
6618 : }
6619 :
6620 : /* timestamptz_izone()
6621 : * Encode timestamp with time zone type with specified time interval as time zone.
6622 : * Returns a timestamp without time zone.
6623 : */
6624 : Datum
6625 6 : timestamptz_izone(PG_FUNCTION_ARGS)
6626 : {
6627 6 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6628 6 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6629 : Timestamp result;
6630 : int tz;
6631 :
6632 6 : if (TIMESTAMP_NOT_FINITE(timestamp))
6633 0 : PG_RETURN_TIMESTAMP(timestamp);
6634 :
6635 6 : if (INTERVAL_NOT_FINITE(zone))
6636 6 : ereport(ERROR,
6637 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6638 : errmsg("interval time zone \"%s\" must be finite",
6639 : DatumGetCString(DirectFunctionCall1(interval_out,
6640 : PointerGetDatum(zone))))));
6641 :
6642 0 : if (zone->month != 0 || zone->day != 0)
6643 0 : ereport(ERROR,
6644 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6645 : errmsg("interval time zone \"%s\" must not include months or days",
6646 : DatumGetCString(DirectFunctionCall1(interval_out,
6647 : PointerGetDatum(zone))))));
6648 :
6649 0 : tz = -(zone->time / USECS_PER_SEC);
6650 :
6651 0 : result = dt2local(timestamp, tz);
6652 :
6653 0 : if (!IS_VALID_TIMESTAMP(result))
6654 0 : ereport(ERROR,
6655 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6656 : errmsg("timestamp out of range")));
6657 :
6658 0 : PG_RETURN_TIMESTAMP(result);
6659 : }
6660 :
6661 : /* generate_series_timestamp()
6662 : * Generate the set of timestamps from start to finish by step
6663 : */
6664 : Datum
6665 432 : generate_series_timestamp(PG_FUNCTION_ARGS)
6666 : {
6667 : FuncCallContext *funcctx;
6668 : generate_series_timestamp_fctx *fctx;
6669 : Timestamp result;
6670 :
6671 : /* stuff done only on the first call of the function */
6672 432 : if (SRF_IS_FIRSTCALL())
6673 : {
6674 22 : Timestamp start = PG_GETARG_TIMESTAMP(0);
6675 22 : Timestamp finish = PG_GETARG_TIMESTAMP(1);
6676 22 : Interval *step = PG_GETARG_INTERVAL_P(2);
6677 : MemoryContext oldcontext;
6678 :
6679 : /* create a function context for cross-call persistence */
6680 22 : funcctx = SRF_FIRSTCALL_INIT();
6681 :
6682 : /*
6683 : * switch to memory context appropriate for multiple function calls
6684 : */
6685 22 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6686 :
6687 : /* allocate memory for user context */
6688 22 : fctx = palloc_object(generate_series_timestamp_fctx);
6689 :
6690 : /*
6691 : * Use fctx to keep state from call to call. Seed current with the
6692 : * original start value
6693 : */
6694 22 : fctx->current = start;
6695 22 : fctx->finish = finish;
6696 22 : fctx->step = *step;
6697 :
6698 : /* Determine sign of the interval */
6699 22 : fctx->step_sign = interval_sign(&fctx->step);
6700 :
6701 22 : if (fctx->step_sign == 0)
6702 3 : ereport(ERROR,
6703 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6704 : errmsg("step size cannot equal zero")));
6705 :
6706 19 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6707 6 : ereport(ERROR,
6708 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6709 : errmsg("step size cannot be infinite")));
6710 :
6711 13 : funcctx->user_fctx = fctx;
6712 13 : MemoryContextSwitchTo(oldcontext);
6713 : }
6714 :
6715 : /* stuff done on every call of the function */
6716 423 : funcctx = SRF_PERCALL_SETUP();
6717 :
6718 : /*
6719 : * get the saved state and use current as the result for this iteration
6720 : */
6721 423 : fctx = funcctx->user_fctx;
6722 423 : result = fctx->current;
6723 :
6724 846 : if (fctx->step_sign > 0 ?
6725 423 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6726 0 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6727 : {
6728 : /* increment current in preparation for next iteration */
6729 413 : fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
6730 : TimestampGetDatum(fctx->current),
6731 : PointerGetDatum(&fctx->step)));
6732 :
6733 : /* do when there is more left to send */
6734 413 : SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
6735 : }
6736 : else
6737 : {
6738 : /* do when there is no more left */
6739 10 : SRF_RETURN_DONE(funcctx);
6740 : }
6741 : }
6742 :
6743 : /* generate_series_timestamptz()
6744 : * Generate the set of timestamps from start to finish by step,
6745 : * doing arithmetic in the specified or session timezone.
6746 : */
6747 : static Datum
6748 31341 : generate_series_timestamptz_internal(FunctionCallInfo fcinfo)
6749 : {
6750 : FuncCallContext *funcctx;
6751 : generate_series_timestamptz_fctx *fctx;
6752 : TimestampTz result;
6753 :
6754 : /* stuff done only on the first call of the function */
6755 31341 : if (SRF_IS_FIRSTCALL())
6756 : {
6757 46 : TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
6758 46 : TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
6759 46 : Interval *step = PG_GETARG_INTERVAL_P(2);
6760 46 : text *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
6761 : MemoryContext oldcontext;
6762 :
6763 : /* create a function context for cross-call persistence */
6764 46 : funcctx = SRF_FIRSTCALL_INIT();
6765 :
6766 : /*
6767 : * switch to memory context appropriate for multiple function calls
6768 : */
6769 46 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6770 :
6771 : /* allocate memory for user context */
6772 46 : fctx = palloc_object(generate_series_timestamptz_fctx);
6773 :
6774 : /*
6775 : * Use fctx to keep state from call to call. Seed current with the
6776 : * original start value
6777 : */
6778 46 : fctx->current = start;
6779 46 : fctx->finish = finish;
6780 46 : fctx->step = *step;
6781 46 : fctx->attimezone = zone ? lookup_timezone(zone) : session_timezone;
6782 :
6783 : /* Determine sign of the interval */
6784 46 : fctx->step_sign = interval_sign(&fctx->step);
6785 :
6786 46 : if (fctx->step_sign == 0)
6787 6 : ereport(ERROR,
6788 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6789 : errmsg("step size cannot equal zero")));
6790 :
6791 40 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6792 6 : ereport(ERROR,
6793 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6794 : errmsg("step size cannot be infinite")));
6795 :
6796 34 : funcctx->user_fctx = fctx;
6797 34 : MemoryContextSwitchTo(oldcontext);
6798 : }
6799 :
6800 : /* stuff done on every call of the function */
6801 31329 : funcctx = SRF_PERCALL_SETUP();
6802 :
6803 : /*
6804 : * get the saved state and use current as the result for this iteration
6805 : */
6806 31329 : fctx = funcctx->user_fctx;
6807 31329 : result = fctx->current;
6808 :
6809 62658 : if (fctx->step_sign > 0 ?
6810 31194 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6811 135 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6812 : {
6813 : /* increment current in preparation for next iteration */
6814 31298 : fctx->current = timestamptz_pl_interval_internal(fctx->current,
6815 : &fctx->step,
6816 : fctx->attimezone);
6817 :
6818 : /* do when there is more left to send */
6819 31298 : SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
6820 : }
6821 : else
6822 : {
6823 : /* do when there is no more left */
6824 31 : SRF_RETURN_DONE(funcctx);
6825 : }
6826 : }
6827 :
6828 : Datum
6829 31206 : generate_series_timestamptz(PG_FUNCTION_ARGS)
6830 : {
6831 31206 : return generate_series_timestamptz_internal(fcinfo);
6832 : }
6833 :
6834 : Datum
6835 135 : generate_series_timestamptz_at_zone(PG_FUNCTION_ARGS)
6836 : {
6837 135 : return generate_series_timestamptz_internal(fcinfo);
6838 : }
6839 :
6840 : /*
6841 : * Planner support function for generate_series(timestamp, timestamp, interval)
6842 : */
6843 : Datum
6844 250 : generate_series_timestamp_support(PG_FUNCTION_ARGS)
6845 : {
6846 250 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6847 250 : Node *ret = NULL;
6848 :
6849 250 : if (IsA(rawreq, SupportRequestRows))
6850 : {
6851 : /* Try to estimate the number of rows returned */
6852 67 : SupportRequestRows *req = (SupportRequestRows *) rawreq;
6853 :
6854 67 : if (is_funcclause(req->node)) /* be paranoid */
6855 : {
6856 67 : List *args = ((FuncExpr *) req->node)->args;
6857 : Node *arg1,
6858 : *arg2,
6859 : *arg3;
6860 :
6861 : /* We can use estimated argument values here */
6862 67 : arg1 = estimate_expression_value(req->root, linitial(args));
6863 67 : arg2 = estimate_expression_value(req->root, lsecond(args));
6864 67 : arg3 = estimate_expression_value(req->root, lthird(args));
6865 :
6866 : /*
6867 : * If any argument is constant NULL, we can safely assume that
6868 : * zero rows are returned. Otherwise, if they're all non-NULL
6869 : * constants, we can calculate the number of rows that will be
6870 : * returned.
6871 : */
6872 67 : if ((IsA(arg1, Const) && ((Const *) arg1)->constisnull) ||
6873 67 : (IsA(arg2, Const) && ((Const *) arg2)->constisnull) ||
6874 67 : (IsA(arg3, Const) && ((Const *) arg3)->constisnull))
6875 : {
6876 0 : req->rows = 0;
6877 0 : ret = (Node *) req;
6878 : }
6879 67 : else if (IsA(arg1, Const) && IsA(arg2, Const) && IsA(arg3, Const))
6880 : {
6881 : Timestamp start,
6882 : finish;
6883 : Interval *step;
6884 : Datum diff;
6885 : double dstep;
6886 : int64 dummy;
6887 :
6888 66 : start = DatumGetTimestamp(((Const *) arg1)->constvalue);
6889 66 : finish = DatumGetTimestamp(((Const *) arg2)->constvalue);
6890 66 : step = DatumGetIntervalP(((Const *) arg3)->constvalue);
6891 :
6892 : /*
6893 : * Perform some prechecks which could cause timestamp_mi to
6894 : * raise an ERROR. It's much better to just return some
6895 : * default estimate than error out in a support function.
6896 : */
6897 66 : if (!TIMESTAMP_NOT_FINITE(start) && !TIMESTAMP_NOT_FINITE(finish) &&
6898 57 : !pg_sub_s64_overflow(finish, start, &dummy))
6899 : {
6900 57 : diff = DirectFunctionCall2(timestamp_mi,
6901 : TimestampGetDatum(finish),
6902 : TimestampGetDatum(start));
6903 :
6904 : #define INTERVAL_TO_MICROSECONDS(i) ((((double) (i)->month * DAYS_PER_MONTH + (i)->day)) * USECS_PER_DAY + (i)->time)
6905 :
6906 57 : dstep = INTERVAL_TO_MICROSECONDS(step);
6907 :
6908 : /* This equation works for either sign of step */
6909 57 : if (dstep != 0.0)
6910 : {
6911 48 : Interval *idiff = DatumGetIntervalP(diff);
6912 48 : double ddiff = INTERVAL_TO_MICROSECONDS(idiff);
6913 :
6914 48 : req->rows = floor(ddiff / dstep + 1.0);
6915 48 : ret = (Node *) req;
6916 : }
6917 : #undef INTERVAL_TO_MICROSECONDS
6918 : }
6919 : }
6920 : }
6921 : }
6922 :
6923 250 : PG_RETURN_POINTER(ret);
6924 : }
6925 :
6926 :
6927 : /* timestamp_at_local()
6928 : * timestamptz_at_local()
6929 : *
6930 : * The regression tests do not like two functions with the same proargs and
6931 : * prosrc but different proname, but the grammar for AT LOCAL needs an
6932 : * overloaded name to handle both types of timestamp, so we make simple
6933 : * wrappers for it.
6934 : */
6935 : Datum
6936 12 : timestamp_at_local(PG_FUNCTION_ARGS)
6937 : {
6938 12 : return timestamp_timestamptz(fcinfo);
6939 : }
6940 :
6941 : Datum
6942 12 : timestamptz_at_local(PG_FUNCTION_ARGS)
6943 : {
6944 12 : return timestamptz_timestamp(fcinfo);
6945 : }
|