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