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 154 : anytimestamp_typmodin(bool istz, ArrayType *ta)
105 : {
106 : int32 *tl;
107 : int n;
108 :
109 154 : 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 154 : if (n != 1)
116 0 : ereport(ERROR,
117 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
118 : errmsg("invalid type modifier")));
119 :
120 154 : return anytimestamp_typmod_check(istz, tl[0]);
121 : }
122 :
123 : /* exported so parse_expr.c can use it */
124 : int32
125 724 : anytimestamp_typmod_check(bool istz, int32 typmod)
126 : {
127 724 : 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 724 : 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 724 : return typmod;
143 : }
144 :
145 : /* common code for timestamptypmodout and timestamptztypmodout */
146 : static char *
147 20 : anytimestamp_typmodout(bool istz, int32 typmod)
148 : {
149 20 : const char *tz = istz ? " with time zone" : " without time zone";
150 :
151 20 : if (typmod >= 0)
152 20 : 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 17560 : timestamp_in(PG_FUNCTION_ARGS)
167 : {
168 17560 : char *str = PG_GETARG_CSTRING(0);
169 : #ifdef NOT_USED
170 : Oid typelem = PG_GETARG_OID(1);
171 : #endif
172 17560 : int32 typmod = PG_GETARG_INT32(2);
173 17560 : Node *escontext = fcinfo->context;
174 : Timestamp result;
175 : fsec_t fsec;
176 : struct pg_tm tt,
177 17560 : *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 17560 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
188 : field, ftype, MAXDATEFIELDS, &nf);
189 17560 : if (dterr == 0)
190 17560 : dterr = DecodeDateTime(field, ftype, nf,
191 : &dtype, tm, &fsec, &tz, &extra);
192 17560 : if (dterr != 0)
193 : {
194 114 : DateTimeParseError(dterr, &extra, str, "timestamp", escontext);
195 24 : PG_RETURN_NULL();
196 : }
197 :
198 17446 : switch (dtype)
199 : {
200 17068 : case DTK_DATE:
201 17068 : 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 17050 : break;
206 :
207 24 : case DTK_EPOCH:
208 24 : result = SetEpochTimestamp();
209 24 : break;
210 :
211 206 : case DTK_LATE:
212 206 : TIMESTAMP_NOEND(result);
213 206 : break;
214 :
215 148 : case DTK_EARLY:
216 148 : TIMESTAMP_NOBEGIN(result);
217 148 : 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 17428 : AdjustTimestampForTypmod(&result, typmod, escontext);
226 :
227 17428 : PG_RETURN_TIMESTAMP(result);
228 : }
229 :
230 : /* timestamp_out()
231 : * Convert a timestamp to external form.
232 : */
233 : Datum
234 43434 : timestamp_out(PG_FUNCTION_ARGS)
235 : {
236 43434 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
237 : char *result;
238 : struct pg_tm tt,
239 43434 : *tm = &tt;
240 : fsec_t fsec;
241 : char buf[MAXDATELEN + 1];
242 :
243 43434 : if (TIMESTAMP_NOT_FINITE(timestamp))
244 530 : EncodeSpecialTimestamp(timestamp, buf);
245 42904 : else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
246 42904 : 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 43434 : result = pstrdup(buf);
253 43434 : 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 36 : timestamptypmodin(PG_FUNCTION_ARGS)
305 : {
306 36 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
307 :
308 36 : PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
309 : }
310 :
311 : Datum
312 10 : timestamptypmodout(PG_FUNCTION_ARGS)
313 : {
314 10 : int32 typmod = PG_GETARG_INT32(0);
315 :
316 10 : 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 125658 : 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 125658 : if (!TIMESTAMP_NOT_FINITE(*time)
391 124870 : && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
392 : {
393 63230 : 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 63230 : if (*time >= INT64CONST(0))
400 : {
401 62588 : *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
402 62588 : TimestampScales[typmod];
403 : }
404 : else
405 : {
406 642 : *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
407 642 : * TimestampScales[typmod]);
408 : }
409 : }
410 :
411 125658 : return true;
412 : }
413 :
414 : /* timestamptz_in()
415 : * Convert a string to internal form.
416 : */
417 : Datum
418 41294 : timestamptz_in(PG_FUNCTION_ARGS)
419 : {
420 41294 : char *str = PG_GETARG_CSTRING(0);
421 : #ifdef NOT_USED
422 : Oid typelem = PG_GETARG_OID(1);
423 : #endif
424 41294 : int32 typmod = PG_GETARG_INT32(2);
425 41294 : Node *escontext = fcinfo->context;
426 : TimestampTz result;
427 : fsec_t fsec;
428 : struct pg_tm tt,
429 41294 : *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 41294 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
440 : field, ftype, MAXDATEFIELDS, &nf);
441 41294 : if (dterr == 0)
442 41294 : dterr = DecodeDateTime(field, ftype, nf,
443 : &dtype, tm, &fsec, &tz, &extra);
444 41294 : if (dterr != 0)
445 : {
446 126 : DateTimeParseError(dterr, &extra, str, "timestamp with time zone",
447 : escontext);
448 24 : PG_RETURN_NULL();
449 : }
450 :
451 41168 : switch (dtype)
452 : {
453 40746 : case DTK_DATE:
454 40746 : 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 40722 : break;
459 :
460 12 : case DTK_EPOCH:
461 12 : result = SetEpochTimestamp();
462 12 : break;
463 :
464 248 : case DTK_LATE:
465 248 : TIMESTAMP_NOEND(result);
466 248 : break;
467 :
468 162 : case DTK_EARLY:
469 162 : TIMESTAMP_NOBEGIN(result);
470 162 : 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 41144 : AdjustTimestampForTypmod(&result, typmod, escontext);
479 :
480 41144 : 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 96 : lookup_timezone(text *zone)
561 : {
562 : char tzname[TZ_STRLEN_MAX + 1];
563 :
564 96 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
565 :
566 96 : 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 70890 : timestamptz_out(PG_FUNCTION_ARGS)
777 : {
778 70890 : TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
779 : char *result;
780 : int tz;
781 : struct pg_tm tt,
782 70890 : *tm = &tt;
783 : fsec_t fsec;
784 : const char *tzn;
785 : char buf[MAXDATELEN + 1];
786 :
787 70890 : if (TIMESTAMP_NOT_FINITE(dt))
788 748 : EncodeSpecialTimestamp(dt, buf);
789 70142 : else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
790 70142 : 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 70890 : result = pstrdup(buf);
797 70890 : 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 118 : timestamptztypmodin(PG_FUNCTION_ARGS)
850 : {
851 118 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
852 :
853 118 : PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
854 : }
855 :
856 : Datum
857 10 : timestamptztypmodout(PG_FUNCTION_ARGS)
858 : {
859 10 : int32 typmod = PG_GETARG_INT32(0);
860 :
861 10 : 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 65340 : interval_in(PG_FUNCTION_ARGS)
892 : {
893 65340 : char *str = PG_GETARG_CSTRING(0);
894 : #ifdef NOT_USED
895 : Oid typelem = PG_GETARG_OID(1);
896 : #endif
897 65340 : int32 typmod = PG_GETARG_INT32(2);
898 65340 : Node *escontext = fcinfo->context;
899 : Interval *result;
900 : struct pg_itm_in tt,
901 65340 : *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 65340 : itm_in->tm_year = 0;
912 65340 : itm_in->tm_mon = 0;
913 65340 : itm_in->tm_mday = 0;
914 65340 : itm_in->tm_usec = 0;
915 :
916 65340 : if (typmod >= 0)
917 336 : range = INTERVAL_RANGE(typmod);
918 : else
919 65004 : range = INTERVAL_FULL_RANGE;
920 :
921 65340 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
922 : ftype, MAXDATEFIELDS, &nf);
923 65340 : if (dterr == 0)
924 65340 : 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 65340 : if (dterr == DTERR_BAD_FORMAT)
929 612 : dterr = DecodeISO8601Interval(str,
930 : &dtype, itm_in);
931 :
932 65340 : 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 64386 : result = (Interval *) palloc(sizeof(Interval));
941 :
942 64386 : switch (dtype)
943 : {
944 63414 : case DTK_DELTA:
945 63414 : 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 63396 : break;
950 :
951 570 : case DTK_LATE:
952 570 : INTERVAL_NOEND(result);
953 570 : break;
954 :
955 402 : case DTK_EARLY:
956 402 : INTERVAL_NOBEGIN(result);
957 402 : break;
958 :
959 0 : default:
960 0 : elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
961 : dtype, str);
962 : }
963 :
964 64368 : AdjustIntervalForTypmod(result, typmod, escontext);
965 :
966 64356 : PG_RETURN_INTERVAL_P(result);
967 : }
968 :
969 : /* interval_out()
970 : * Convert a time span to external form.
971 : */
972 : Datum
973 16314 : interval_out(PG_FUNCTION_ARGS)
974 : {
975 16314 : Interval *span = PG_GETARG_INTERVAL_P(0);
976 : char *result;
977 : struct pg_itm tt,
978 16314 : *itm = &tt;
979 : char buf[MAXDATELEN + 1];
980 :
981 16314 : if (INTERVAL_NOT_FINITE(span))
982 2024 : EncodeSpecialInterval(span, buf);
983 : else
984 : {
985 14290 : interval2itm(*span, itm);
986 14290 : EncodeInterval(itm, IntervalStyle, buf);
987 : }
988 :
989 16314 : result = pstrdup(buf);
990 16314 : 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 64584 : 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 64584 : if (INTERVAL_NOT_FINITE(interval))
1375 1020 : 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 63564 : 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 72 : 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 6 : 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 63552 : 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 1326 : EncodeSpecialTimestamp(Timestamp dt, char *str)
1588 : {
1589 1326 : if (TIMESTAMP_IS_NOBEGIN(dt))
1590 646 : strcpy(str, EARLY);
1591 680 : else if (TIMESTAMP_IS_NOEND(dt))
1592 680 : strcpy(str, LATE);
1593 : else /* shouldn't happen */
1594 0 : elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
1595 1326 : }
1596 :
1597 : static void
1598 2024 : EncodeSpecialInterval(const Interval *interval, char *str)
1599 : {
1600 2024 : if (INTERVAL_IS_NOBEGIN(interval))
1601 994 : strcpy(str, EARLY);
1602 1030 : else if (INTERVAL_IS_NOEND(interval))
1603 1030 : strcpy(str, LATE);
1604 : else /* shouldn't happen */
1605 0 : elog(ERROR, "invalid argument for EncodeSpecialInterval");
1606 2024 : }
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 24 : clock_timestamp(PG_FUNCTION_ARGS)
1622 : {
1623 24 : 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 9921528 : GetCurrentTimestamp(void)
1646 : {
1647 : TimestampTz result;
1648 : struct timeval tp;
1649 :
1650 9921528 : gettimeofday(&tp, NULL);
1651 :
1652 9921528 : result = (TimestampTz) tp.tv_sec -
1653 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1654 9921528 : result = (result * USECS_PER_SEC) + tp.tv_usec;
1655 :
1656 9921528 : 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 1247786 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
1722 : long *secs, int *microsecs)
1723 : {
1724 1247786 : TimestampTz diff = stop_time - start_time;
1725 :
1726 1247786 : if (diff <= 0)
1727 : {
1728 252 : *secs = 0;
1729 252 : *microsecs = 0;
1730 : }
1731 : else
1732 : {
1733 1247534 : *secs = (long) (diff / USECS_PER_SEC);
1734 1247534 : *microsecs = (int) (diff % USECS_PER_SEC);
1735 : }
1736 1247786 : }
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 538372 : TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
1758 : {
1759 : TimestampTz diff;
1760 :
1761 : /* Deal with zero or negative elapsed time quickly. */
1762 538372 : if (start_time >= stop_time)
1763 14 : return 0;
1764 : /* To not fail with timestamp infinities, we must detect overflow. */
1765 538358 : if (pg_sub_s64_overflow(stop_time, start_time, &diff))
1766 0 : return (long) INT_MAX;
1767 538358 : if (diff >= (INT_MAX * INT64CONST(1000) - 999))
1768 0 : return (long) INT_MAX;
1769 : else
1770 538358 : 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 1220134 : TimestampDifferenceExceeds(TimestampTz start_time,
1782 : TimestampTz stop_time,
1783 : int msec)
1784 : {
1785 1220134 : TimestampTz diff = stop_time - start_time;
1786 :
1787 1220134 : 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 42836 : time_t_to_timestamptz(pg_time_t tm)
1821 : {
1822 : TimestampTz result;
1823 :
1824 42836 : result = (TimestampTz) tm -
1825 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1826 42836 : result *= USECS_PER_SEC;
1827 :
1828 42836 : 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 48030 : timestamptz_to_time_t(TimestampTz t)
1843 : {
1844 : pg_time_t result;
1845 :
1846 48030 : result = (pg_time_t) (t / USECS_PER_SEC +
1847 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
1848 :
1849 48030 : 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 2638 : timestamptz_to_str(TimestampTz t)
1863 : {
1864 : static char buf[MAXDATELEN + 1];
1865 : int tz;
1866 : struct pg_tm tt,
1867 2638 : *tm = &tt;
1868 : fsec_t fsec;
1869 : const char *tzn;
1870 :
1871 2638 : if (TIMESTAMP_NOT_FINITE(t))
1872 0 : EncodeSpecialTimestamp(t, buf);
1873 2638 : else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
1874 2638 : EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1875 : else
1876 0 : strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1877 :
1878 2638 : return buf;
1879 : }
1880 :
1881 :
1882 : void
1883 311448 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
1884 : {
1885 : TimeOffset time;
1886 :
1887 311448 : time = jd;
1888 :
1889 311448 : *hour = time / USECS_PER_HOUR;
1890 311448 : time -= (*hour) * USECS_PER_HOUR;
1891 311448 : *min = time / USECS_PER_MINUTE;
1892 311448 : time -= (*min) * USECS_PER_MINUTE;
1893 311448 : *sec = time / USECS_PER_SEC;
1894 311448 : *fsec = time - (*sec * USECS_PER_SEC);
1895 311448 : } /* 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 311436 : 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 311436 : if (attimezone == NULL)
1918 238594 : attimezone = session_timezone;
1919 :
1920 311436 : time = dt;
1921 311436 : TMODULO(time, date, USECS_PER_DAY);
1922 :
1923 311436 : if (time < INT64CONST(0))
1924 : {
1925 102240 : time += USECS_PER_DAY;
1926 102240 : date -= 1;
1927 : }
1928 :
1929 : /* add offset to go from J2000 back to standard Julian date */
1930 311436 : date += POSTGRES_EPOCH_JDATE;
1931 :
1932 : /* Julian day routine does not work for negative Julian days */
1933 311436 : if (date < 0 || date > (Timestamp) INT_MAX)
1934 0 : return -1;
1935 :
1936 311436 : j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1937 311436 : dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
1938 :
1939 : /* Done if no TZ conversion wanted */
1940 311436 : if (tzp == NULL)
1941 : {
1942 85414 : tm->tm_isdst = -1;
1943 85414 : tm->tm_gmtoff = 0;
1944 85414 : tm->tm_zone = NULL;
1945 85414 : if (tzn != NULL)
1946 0 : *tzn = NULL;
1947 85414 : 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 226022 : dt = (dt - *fsec) / USECS_PER_SEC +
1961 : (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1962 226022 : utime = (pg_time_t) dt;
1963 226022 : if ((Timestamp) utime == dt)
1964 : {
1965 226022 : struct pg_tm *tx = pg_localtime(&utime, attimezone);
1966 :
1967 226022 : tm->tm_year = tx->tm_year + 1900;
1968 226022 : tm->tm_mon = tx->tm_mon + 1;
1969 226022 : tm->tm_mday = tx->tm_mday;
1970 226022 : tm->tm_hour = tx->tm_hour;
1971 226022 : tm->tm_min = tx->tm_min;
1972 226022 : tm->tm_sec = tx->tm_sec;
1973 226022 : tm->tm_isdst = tx->tm_isdst;
1974 226022 : tm->tm_gmtoff = tx->tm_gmtoff;
1975 226022 : tm->tm_zone = tx->tm_zone;
1976 226022 : *tzp = -tm->tm_gmtoff;
1977 226022 : if (tzn != NULL)
1978 86984 : *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 226022 : 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 220948 : 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 220948 : 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 220936 : date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
2019 220936 : time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
2020 :
2021 220936 : 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 220930 : if (tzp != NULL)
2028 104538 : *result = dt2local(*result, -(*tzp));
2029 :
2030 : /* final range check catches just-out-of-range timestamps */
2031 220930 : if (!IS_VALID_TIMESTAMP(*result))
2032 : {
2033 28 : *result = 0; /* keep compiler quiet */
2034 28 : return -1;
2035 : }
2036 :
2037 220902 : 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 16410 : interval2itm(Interval span, struct pg_itm *itm)
2048 : {
2049 : TimeOffset time;
2050 : TimeOffset tfrac;
2051 :
2052 16410 : itm->tm_year = span.month / MONTHS_PER_YEAR;
2053 16410 : itm->tm_mon = span.month % MONTHS_PER_YEAR;
2054 16410 : itm->tm_mday = span.day;
2055 16410 : time = span.time;
2056 :
2057 16410 : tfrac = time / USECS_PER_HOUR;
2058 16410 : time -= tfrac * USECS_PER_HOUR;
2059 16410 : itm->tm_hour = tfrac;
2060 16410 : tfrac = time / USECS_PER_MINUTE;
2061 16410 : time -= tfrac * USECS_PER_MINUTE;
2062 16410 : itm->tm_min = (int) tfrac;
2063 16410 : tfrac = time / USECS_PER_SEC;
2064 16410 : time -= tfrac * USECS_PER_SEC;
2065 16410 : itm->tm_sec = (int) tfrac;
2066 16410 : itm->tm_usec = (int) time;
2067 16410 : }
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 77884 : itmin2interval(struct pg_itm_in *itm_in, Interval *span)
2116 : {
2117 77884 : int64 total_months = (int64) itm_in->tm_year * MONTHS_PER_YEAR + itm_in->tm_mon;
2118 :
2119 77884 : if (total_months > INT_MAX || total_months < INT_MIN)
2120 18 : return -1;
2121 77866 : span->month = (int32) total_months;
2122 77866 : span->day = itm_in->tm_mday;
2123 77866 : span->time = itm_in->tm_usec;
2124 77866 : return 0;
2125 : }
2126 :
2127 : static TimeOffset
2128 220936 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
2129 : {
2130 220936 : return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
2131 : }
2132 :
2133 : static Timestamp
2134 121202 : dt2local(Timestamp dt, int timezone)
2135 : {
2136 121202 : dt -= (timezone * USECS_PER_SEC);
2137 121202 : 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 28372 : GetEpochTime(struct pg_tm *tm)
2169 : {
2170 : struct pg_tm *t0;
2171 28372 : pg_time_t epoch = 0;
2172 :
2173 28372 : t0 = pg_gmtime(&epoch);
2174 :
2175 28372 : if (t0 == NULL)
2176 0 : elog(ERROR, "could not convert epoch to timestamp: %m");
2177 :
2178 28372 : tm->tm_year = t0->tm_year;
2179 28372 : tm->tm_mon = t0->tm_mon;
2180 28372 : tm->tm_mday = t0->tm_mday;
2181 28372 : tm->tm_hour = t0->tm_hour;
2182 28372 : tm->tm_min = t0->tm_min;
2183 28372 : tm->tm_sec = t0->tm_sec;
2184 :
2185 28372 : tm->tm_year += 1900;
2186 28372 : tm->tm_mon++;
2187 28372 : }
2188 :
2189 : Timestamp
2190 28366 : SetEpochTimestamp(void)
2191 : {
2192 : Timestamp dt;
2193 : struct pg_tm tt,
2194 28366 : *tm = &tt;
2195 :
2196 28366 : GetEpochTime(tm);
2197 : /* we don't bother to test for failure ... */
2198 28366 : tm2timestamp(tm, 0, NULL, &dt);
2199 :
2200 28366 : 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 467448 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
2211 : {
2212 467448 : return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2213 : }
2214 :
2215 : Datum
2216 28746 : timestamp_eq(PG_FUNCTION_ARGS)
2217 : {
2218 28746 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2219 28746 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2220 :
2221 28746 : 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 177918 : timestamp_lt(PG_FUNCTION_ARGS)
2235 : {
2236 177918 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2237 177918 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2238 :
2239 177918 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2240 : }
2241 :
2242 : Datum
2243 99432 : timestamp_gt(PG_FUNCTION_ARGS)
2244 : {
2245 99432 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2246 99432 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2247 :
2248 99432 : 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 41838 : timestamp_cmp(PG_FUNCTION_ARGS)
2271 : {
2272 41838 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2273 41838 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2274 :
2275 41838 : PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
2276 : }
2277 :
2278 : Datum
2279 568 : timestamp_sortsupport(PG_FUNCTION_ARGS)
2280 : {
2281 568 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
2282 :
2283 568 : ssup->comparator = ssup_datum_signed_cmp;
2284 568 : PG_RETURN_VOID();
2285 : }
2286 :
2287 : /* note: this is used for timestamptz also */
2288 : static Datum
2289 0 : timestamp_decrement(Relation rel, Datum existing, bool *underflow)
2290 : {
2291 0 : Timestamp texisting = DatumGetTimestamp(existing);
2292 :
2293 0 : if (texisting == PG_INT64_MIN)
2294 : {
2295 : /* return value is undefined */
2296 0 : *underflow = true;
2297 0 : return (Datum) 0;
2298 : }
2299 :
2300 0 : *underflow = false;
2301 0 : return TimestampGetDatum(texisting - 1);
2302 : }
2303 :
2304 : /* note: this is used for timestamptz also */
2305 : static Datum
2306 0 : timestamp_increment(Relation rel, Datum existing, bool *overflow)
2307 : {
2308 0 : Timestamp texisting = DatumGetTimestamp(existing);
2309 :
2310 0 : if (texisting == PG_INT64_MAX)
2311 : {
2312 : /* return value is undefined */
2313 0 : *overflow = true;
2314 0 : return (Datum) 0;
2315 : }
2316 :
2317 0 : *overflow = false;
2318 0 : return TimestampGetDatum(texisting + 1);
2319 : }
2320 :
2321 : Datum
2322 0 : timestamp_skipsupport(PG_FUNCTION_ARGS)
2323 : {
2324 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
2325 :
2326 0 : sksup->decrement = timestamp_decrement;
2327 0 : sksup->increment = timestamp_increment;
2328 0 : sksup->low_elem = TimestampGetDatum(PG_INT64_MIN);
2329 0 : sksup->high_elem = TimestampGetDatum(PG_INT64_MAX);
2330 :
2331 0 : PG_RETURN_VOID();
2332 : }
2333 :
2334 : Datum
2335 6494 : timestamp_hash(PG_FUNCTION_ARGS)
2336 : {
2337 6494 : return hashint8(fcinfo);
2338 : }
2339 :
2340 : Datum
2341 60 : timestamp_hash_extended(PG_FUNCTION_ARGS)
2342 : {
2343 60 : return hashint8extended(fcinfo);
2344 : }
2345 :
2346 : Datum
2347 0 : timestamptz_hash(PG_FUNCTION_ARGS)
2348 : {
2349 0 : return hashint8(fcinfo);
2350 : }
2351 :
2352 : Datum
2353 0 : timestamptz_hash_extended(PG_FUNCTION_ARGS)
2354 : {
2355 0 : return hashint8extended(fcinfo);
2356 : }
2357 :
2358 : /*
2359 : * Cross-type comparison functions for timestamp vs timestamptz
2360 : */
2361 :
2362 : int32
2363 16074 : timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
2364 : {
2365 : TimestampTz dt1;
2366 : int overflow;
2367 :
2368 16074 : dt1 = timestamp2timestamptz_opt_overflow(timestampVal, &overflow);
2369 16074 : if (overflow > 0)
2370 : {
2371 : /* dt1 is larger than any finite timestamp, but less than infinity */
2372 0 : return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
2373 : }
2374 16074 : if (overflow < 0)
2375 : {
2376 : /* dt1 is less than any finite timestamp, but more than -infinity */
2377 12 : return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
2378 : }
2379 :
2380 16062 : return timestamptz_cmp_internal(dt1, dt2);
2381 : }
2382 :
2383 : Datum
2384 1812 : timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
2385 : {
2386 1812 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2387 1812 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2388 :
2389 1812 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) == 0);
2390 : }
2391 :
2392 : Datum
2393 0 : timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
2394 : {
2395 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2396 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2397 :
2398 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) != 0);
2399 : }
2400 :
2401 : Datum
2402 3204 : timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
2403 : {
2404 3204 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2405 3204 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2406 :
2407 3204 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) < 0);
2408 : }
2409 :
2410 : Datum
2411 3198 : timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
2412 : {
2413 3198 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2414 3198 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2415 :
2416 3198 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) > 0);
2417 : }
2418 :
2419 : Datum
2420 3798 : timestamp_le_timestamptz(PG_FUNCTION_ARGS)
2421 : {
2422 3798 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2423 3798 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2424 :
2425 3798 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) <= 0);
2426 : }
2427 :
2428 : Datum
2429 3504 : timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
2430 : {
2431 3504 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2432 3504 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2433 :
2434 3504 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) >= 0);
2435 : }
2436 :
2437 : Datum
2438 106 : timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
2439 : {
2440 106 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
2441 106 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2442 :
2443 106 : PG_RETURN_INT32(timestamp_cmp_timestamptz_internal(timestampVal, dt2));
2444 : }
2445 :
2446 : Datum
2447 0 : timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
2448 : {
2449 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2450 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2451 :
2452 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) == 0);
2453 : }
2454 :
2455 : Datum
2456 96 : timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
2457 : {
2458 96 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2459 96 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2460 :
2461 96 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) != 0);
2462 : }
2463 :
2464 : Datum
2465 0 : timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
2466 : {
2467 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2468 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2469 :
2470 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) > 0);
2471 : }
2472 :
2473 : Datum
2474 0 : timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
2475 : {
2476 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2477 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2478 :
2479 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) < 0);
2480 : }
2481 :
2482 : Datum
2483 0 : timestamptz_le_timestamp(PG_FUNCTION_ARGS)
2484 : {
2485 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2486 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2487 :
2488 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) >= 0);
2489 : }
2490 :
2491 : Datum
2492 6 : timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
2493 : {
2494 6 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2495 6 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2496 :
2497 6 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) <= 0);
2498 : }
2499 :
2500 : Datum
2501 134 : timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
2502 : {
2503 134 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
2504 134 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
2505 :
2506 134 : PG_RETURN_INT32(-timestamp_cmp_timestamptz_internal(timestampVal, dt1));
2507 : }
2508 :
2509 :
2510 : /*
2511 : * interval_relop - is interval1 relop interval2
2512 : *
2513 : * Interval comparison is based on converting interval values to a linear
2514 : * representation expressed in the units of the time field (microseconds,
2515 : * in the case of integer timestamps) with days assumed to be always 24 hours
2516 : * and months assumed to be always 30 days. To avoid overflow, we need a
2517 : * wider-than-int64 datatype for the linear representation, so use INT128.
2518 : */
2519 :
2520 : static inline INT128
2521 274960 : interval_cmp_value(const Interval *interval)
2522 : {
2523 : INT128 span;
2524 : int64 days;
2525 :
2526 : /*
2527 : * Combine the month and day fields into an integral number of days.
2528 : * Because the inputs are int32, int64 arithmetic suffices here.
2529 : */
2530 274960 : days = interval->month * INT64CONST(30);
2531 274960 : days += interval->day;
2532 :
2533 : /* Widen time field to 128 bits */
2534 274960 : span = int64_to_int128(interval->time);
2535 :
2536 : /* Scale up days to microseconds, forming a 128-bit product */
2537 274960 : int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
2538 :
2539 274960 : return span;
2540 : }
2541 :
2542 : static int
2543 133868 : interval_cmp_internal(const Interval *interval1, const Interval *interval2)
2544 : {
2545 133868 : INT128 span1 = interval_cmp_value(interval1);
2546 133868 : INT128 span2 = interval_cmp_value(interval2);
2547 :
2548 133868 : return int128_compare(span1, span2);
2549 : }
2550 :
2551 : static int
2552 4886 : interval_sign(const Interval *interval)
2553 : {
2554 4886 : INT128 span = interval_cmp_value(interval);
2555 4886 : INT128 zero = int64_to_int128(0);
2556 :
2557 4886 : return int128_compare(span, zero);
2558 : }
2559 :
2560 : Datum
2561 14286 : interval_eq(PG_FUNCTION_ARGS)
2562 : {
2563 14286 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2564 14286 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2565 :
2566 14286 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
2567 : }
2568 :
2569 : Datum
2570 108 : interval_ne(PG_FUNCTION_ARGS)
2571 : {
2572 108 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2573 108 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2574 :
2575 108 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
2576 : }
2577 :
2578 : Datum
2579 30968 : interval_lt(PG_FUNCTION_ARGS)
2580 : {
2581 30968 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2582 30968 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2583 :
2584 30968 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
2585 : }
2586 :
2587 : Datum
2588 11326 : interval_gt(PG_FUNCTION_ARGS)
2589 : {
2590 11326 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2591 11326 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2592 :
2593 11326 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
2594 : }
2595 :
2596 : Datum
2597 6414 : interval_le(PG_FUNCTION_ARGS)
2598 : {
2599 6414 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2600 6414 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2601 :
2602 6414 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
2603 : }
2604 :
2605 : Datum
2606 5928 : interval_ge(PG_FUNCTION_ARGS)
2607 : {
2608 5928 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2609 5928 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2610 :
2611 5928 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
2612 : }
2613 :
2614 : Datum
2615 63950 : interval_cmp(PG_FUNCTION_ARGS)
2616 : {
2617 63950 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2618 63950 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2619 :
2620 63950 : PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
2621 : }
2622 :
2623 : /*
2624 : * Hashing for intervals
2625 : *
2626 : * We must produce equal hashvals for values that interval_cmp_internal()
2627 : * considers equal. So, compute the net span the same way it does,
2628 : * and then hash that.
2629 : */
2630 : Datum
2631 2278 : interval_hash(PG_FUNCTION_ARGS)
2632 : {
2633 2278 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2634 2278 : INT128 span = interval_cmp_value(interval);
2635 : int64 span64;
2636 :
2637 : /*
2638 : * Use only the least significant 64 bits for hashing. The upper 64 bits
2639 : * seldom add any useful information, and besides we must do it like this
2640 : * for compatibility with hashes calculated before use of INT128 was
2641 : * introduced.
2642 : */
2643 2278 : span64 = int128_to_int64(span);
2644 :
2645 2278 : return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
2646 : }
2647 :
2648 : Datum
2649 60 : interval_hash_extended(PG_FUNCTION_ARGS)
2650 : {
2651 60 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2652 60 : INT128 span = interval_cmp_value(interval);
2653 : int64 span64;
2654 :
2655 : /* Same approach as interval_hash */
2656 60 : span64 = int128_to_int64(span);
2657 :
2658 60 : return DirectFunctionCall2(hashint8extended, Int64GetDatumFast(span64),
2659 : PG_GETARG_DATUM(1));
2660 : }
2661 :
2662 : /* overlaps_timestamp() --- implements the SQL OVERLAPS operator.
2663 : *
2664 : * Algorithm is per SQL spec. This is much harder than you'd think
2665 : * because the spec requires us to deliver a non-null answer in some cases
2666 : * where some of the inputs are null.
2667 : */
2668 : Datum
2669 72 : overlaps_timestamp(PG_FUNCTION_ARGS)
2670 : {
2671 : /*
2672 : * The arguments are Timestamps, but we leave them as generic Datums to
2673 : * avoid unnecessary conversions between value and reference forms --- not
2674 : * to mention possible dereferences of null pointers.
2675 : */
2676 72 : Datum ts1 = PG_GETARG_DATUM(0);
2677 72 : Datum te1 = PG_GETARG_DATUM(1);
2678 72 : Datum ts2 = PG_GETARG_DATUM(2);
2679 72 : Datum te2 = PG_GETARG_DATUM(3);
2680 72 : bool ts1IsNull = PG_ARGISNULL(0);
2681 72 : bool te1IsNull = PG_ARGISNULL(1);
2682 72 : bool ts2IsNull = PG_ARGISNULL(2);
2683 72 : bool te2IsNull = PG_ARGISNULL(3);
2684 :
2685 : #define TIMESTAMP_GT(t1,t2) \
2686 : DatumGetBool(DirectFunctionCall2(timestamp_gt,t1,t2))
2687 : #define TIMESTAMP_LT(t1,t2) \
2688 : DatumGetBool(DirectFunctionCall2(timestamp_lt,t1,t2))
2689 :
2690 : /*
2691 : * If both endpoints of interval 1 are null, the result is null (unknown).
2692 : * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2693 : * take ts1 as the lesser endpoint.
2694 : */
2695 72 : if (ts1IsNull)
2696 : {
2697 0 : if (te1IsNull)
2698 0 : PG_RETURN_NULL();
2699 : /* swap null for non-null */
2700 0 : ts1 = te1;
2701 0 : te1IsNull = true;
2702 : }
2703 72 : else if (!te1IsNull)
2704 : {
2705 72 : if (TIMESTAMP_GT(ts1, te1))
2706 : {
2707 0 : Datum tt = ts1;
2708 :
2709 0 : ts1 = te1;
2710 0 : te1 = tt;
2711 : }
2712 : }
2713 :
2714 : /* Likewise for interval 2. */
2715 72 : if (ts2IsNull)
2716 : {
2717 0 : if (te2IsNull)
2718 0 : PG_RETURN_NULL();
2719 : /* swap null for non-null */
2720 0 : ts2 = te2;
2721 0 : te2IsNull = true;
2722 : }
2723 72 : else if (!te2IsNull)
2724 : {
2725 72 : if (TIMESTAMP_GT(ts2, te2))
2726 : {
2727 0 : Datum tt = ts2;
2728 :
2729 0 : ts2 = te2;
2730 0 : te2 = tt;
2731 : }
2732 : }
2733 :
2734 : /*
2735 : * At this point neither ts1 nor ts2 is null, so we can consider three
2736 : * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2737 : */
2738 72 : if (TIMESTAMP_GT(ts1, ts2))
2739 : {
2740 : /*
2741 : * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2742 : * in the presence of nulls it's not quite completely so.
2743 : */
2744 0 : if (te2IsNull)
2745 0 : PG_RETURN_NULL();
2746 0 : if (TIMESTAMP_LT(ts1, te2))
2747 0 : PG_RETURN_BOOL(true);
2748 0 : if (te1IsNull)
2749 0 : PG_RETURN_NULL();
2750 :
2751 : /*
2752 : * If te1 is not null then we had ts1 <= te1 above, and we just found
2753 : * ts1 >= te2, hence te1 >= te2.
2754 : */
2755 0 : PG_RETURN_BOOL(false);
2756 : }
2757 72 : else if (TIMESTAMP_LT(ts1, ts2))
2758 : {
2759 : /* This case is ts2 < te1 OR te2 < te1 */
2760 60 : if (te1IsNull)
2761 0 : PG_RETURN_NULL();
2762 60 : if (TIMESTAMP_LT(ts2, te1))
2763 24 : PG_RETURN_BOOL(true);
2764 36 : if (te2IsNull)
2765 0 : PG_RETURN_NULL();
2766 :
2767 : /*
2768 : * If te2 is not null then we had ts2 <= te2 above, and we just found
2769 : * ts2 >= te1, hence te2 >= te1.
2770 : */
2771 36 : PG_RETURN_BOOL(false);
2772 : }
2773 : else
2774 : {
2775 : /*
2776 : * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2777 : * rather silly way of saying "true if both are non-null, else null".
2778 : */
2779 12 : if (te1IsNull || te2IsNull)
2780 0 : PG_RETURN_NULL();
2781 12 : PG_RETURN_BOOL(true);
2782 : }
2783 :
2784 : #undef TIMESTAMP_GT
2785 : #undef TIMESTAMP_LT
2786 : }
2787 :
2788 :
2789 : /*----------------------------------------------------------
2790 : * "Arithmetic" operators on date/times.
2791 : *---------------------------------------------------------*/
2792 :
2793 : Datum
2794 0 : timestamp_smaller(PG_FUNCTION_ARGS)
2795 : {
2796 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2797 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2798 : Timestamp result;
2799 :
2800 : /* use timestamp_cmp_internal to be sure this agrees with comparisons */
2801 0 : if (timestamp_cmp_internal(dt1, dt2) < 0)
2802 0 : result = dt1;
2803 : else
2804 0 : result = dt2;
2805 0 : PG_RETURN_TIMESTAMP(result);
2806 : }
2807 :
2808 : Datum
2809 84 : timestamp_larger(PG_FUNCTION_ARGS)
2810 : {
2811 84 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2812 84 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2813 : Timestamp result;
2814 :
2815 84 : if (timestamp_cmp_internal(dt1, dt2) > 0)
2816 0 : result = dt1;
2817 : else
2818 84 : result = dt2;
2819 84 : PG_RETURN_TIMESTAMP(result);
2820 : }
2821 :
2822 :
2823 : Datum
2824 6452 : timestamp_mi(PG_FUNCTION_ARGS)
2825 : {
2826 6452 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2827 6452 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2828 : Interval *result;
2829 :
2830 6452 : result = (Interval *) palloc(sizeof(Interval));
2831 :
2832 : /*
2833 : * Handle infinities.
2834 : *
2835 : * We treat anything that amounts to "infinity - infinity" as an error,
2836 : * since the interval type has nothing equivalent to NaN.
2837 : */
2838 6452 : if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
2839 : {
2840 84 : if (TIMESTAMP_IS_NOBEGIN(dt1))
2841 : {
2842 36 : if (TIMESTAMP_IS_NOBEGIN(dt2))
2843 12 : ereport(ERROR,
2844 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2845 : errmsg("interval out of range")));
2846 : else
2847 24 : INTERVAL_NOBEGIN(result);
2848 : }
2849 48 : else if (TIMESTAMP_IS_NOEND(dt1))
2850 : {
2851 48 : if (TIMESTAMP_IS_NOEND(dt2))
2852 12 : ereport(ERROR,
2853 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2854 : errmsg("interval out of range")));
2855 : else
2856 36 : INTERVAL_NOEND(result);
2857 : }
2858 0 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
2859 0 : INTERVAL_NOEND(result);
2860 : else /* TIMESTAMP_IS_NOEND(dt2) */
2861 0 : INTERVAL_NOBEGIN(result);
2862 :
2863 60 : PG_RETURN_INTERVAL_P(result);
2864 : }
2865 :
2866 6368 : if (unlikely(pg_sub_s64_overflow(dt1, dt2, &result->time)))
2867 12 : ereport(ERROR,
2868 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2869 : errmsg("interval out of range")));
2870 :
2871 6356 : result->month = 0;
2872 6356 : result->day = 0;
2873 :
2874 : /*----------
2875 : * This is wrong, but removing it breaks a lot of regression tests.
2876 : * For example:
2877 : *
2878 : * test=> SET timezone = 'EST5EDT';
2879 : * test=> SELECT
2880 : * test-> ('2005-10-30 13:22:00-05'::timestamptz -
2881 : * test(> '2005-10-29 13:22:00-04'::timestamptz);
2882 : * ?column?
2883 : * ----------------
2884 : * 1 day 01:00:00
2885 : * (1 row)
2886 : *
2887 : * so adding that to the first timestamp gets:
2888 : *
2889 : * test=> SELECT
2890 : * test-> ('2005-10-29 13:22:00-04'::timestamptz +
2891 : * test(> ('2005-10-30 13:22:00-05'::timestamptz -
2892 : * test(> '2005-10-29 13:22:00-04'::timestamptz)) at time zone 'EST';
2893 : * timezone
2894 : * --------------------
2895 : * 2005-10-30 14:22:00
2896 : * (1 row)
2897 : *----------
2898 : */
2899 6356 : result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2900 : IntervalPGetDatum(result)));
2901 :
2902 6356 : PG_RETURN_INTERVAL_P(result);
2903 : }
2904 :
2905 : /*
2906 : * interval_justify_interval()
2907 : *
2908 : * Adjust interval so 'month', 'day', and 'time' portions are within
2909 : * customary bounds. Specifically:
2910 : *
2911 : * 0 <= abs(time) < 24 hours
2912 : * 0 <= abs(day) < 30 days
2913 : *
2914 : * Also, the sign bit on all three fields is made equal, so either
2915 : * all three fields are negative or all are positive.
2916 : */
2917 : Datum
2918 66 : interval_justify_interval(PG_FUNCTION_ARGS)
2919 : {
2920 66 : Interval *span = PG_GETARG_INTERVAL_P(0);
2921 : Interval *result;
2922 : TimeOffset wholeday;
2923 : int32 wholemonth;
2924 :
2925 66 : result = (Interval *) palloc(sizeof(Interval));
2926 66 : result->month = span->month;
2927 66 : result->day = span->day;
2928 66 : result->time = span->time;
2929 :
2930 : /* do nothing for infinite intervals */
2931 66 : if (INTERVAL_NOT_FINITE(result))
2932 12 : PG_RETURN_INTERVAL_P(result);
2933 :
2934 : /* pre-justify days if it might prevent overflow */
2935 54 : if ((result->day > 0 && result->time > 0) ||
2936 48 : (result->day < 0 && result->time < 0))
2937 : {
2938 12 : wholemonth = result->day / DAYS_PER_MONTH;
2939 12 : result->day -= wholemonth * DAYS_PER_MONTH;
2940 12 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
2941 0 : ereport(ERROR,
2942 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2943 : errmsg("interval out of range")));
2944 : }
2945 :
2946 : /*
2947 : * Since TimeOffset is int64, abs(wholeday) can't exceed about 1.07e8. If
2948 : * we pre-justified then abs(result->day) is less than DAYS_PER_MONTH, so
2949 : * this addition can't overflow. If we didn't pre-justify, then day and
2950 : * time are of different signs, so it still can't overflow.
2951 : */
2952 54 : TMODULO(result->time, wholeday, USECS_PER_DAY);
2953 54 : result->day += wholeday;
2954 :
2955 54 : wholemonth = result->day / DAYS_PER_MONTH;
2956 54 : result->day -= wholemonth * DAYS_PER_MONTH;
2957 54 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
2958 24 : ereport(ERROR,
2959 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2960 : errmsg("interval out of range")));
2961 :
2962 30 : if (result->month > 0 &&
2963 18 : (result->day < 0 || (result->day == 0 && result->time < 0)))
2964 : {
2965 6 : result->day += DAYS_PER_MONTH;
2966 6 : result->month--;
2967 : }
2968 24 : else if (result->month < 0 &&
2969 12 : (result->day > 0 || (result->day == 0 && result->time > 0)))
2970 : {
2971 0 : result->day -= DAYS_PER_MONTH;
2972 0 : result->month++;
2973 : }
2974 :
2975 30 : if (result->day > 0 && result->time < 0)
2976 : {
2977 6 : result->time += USECS_PER_DAY;
2978 6 : result->day--;
2979 : }
2980 24 : else if (result->day < 0 && result->time > 0)
2981 : {
2982 0 : result->time -= USECS_PER_DAY;
2983 0 : result->day++;
2984 : }
2985 :
2986 30 : PG_RETURN_INTERVAL_P(result);
2987 : }
2988 :
2989 : /*
2990 : * interval_justify_hours()
2991 : *
2992 : * Adjust interval so 'time' contains less than a whole day, adding
2993 : * the excess to 'day'. This is useful for
2994 : * situations (such as non-TZ) where '1 day' = '24 hours' is valid,
2995 : * e.g. interval subtraction and division.
2996 : */
2997 : Datum
2998 8360 : interval_justify_hours(PG_FUNCTION_ARGS)
2999 : {
3000 8360 : Interval *span = PG_GETARG_INTERVAL_P(0);
3001 : Interval *result;
3002 : TimeOffset wholeday;
3003 :
3004 8360 : result = (Interval *) palloc(sizeof(Interval));
3005 8360 : result->month = span->month;
3006 8360 : result->day = span->day;
3007 8360 : result->time = span->time;
3008 :
3009 : /* do nothing for infinite intervals */
3010 8360 : if (INTERVAL_NOT_FINITE(result))
3011 12 : PG_RETURN_INTERVAL_P(result);
3012 :
3013 8348 : TMODULO(result->time, wholeday, USECS_PER_DAY);
3014 8348 : if (pg_add_s32_overflow(result->day, wholeday, &result->day))
3015 6 : ereport(ERROR,
3016 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3017 : errmsg("interval out of range")));
3018 :
3019 8342 : if (result->day > 0 && result->time < 0)
3020 : {
3021 0 : result->time += USECS_PER_DAY;
3022 0 : result->day--;
3023 : }
3024 8342 : else if (result->day < 0 && result->time > 0)
3025 : {
3026 0 : result->time -= USECS_PER_DAY;
3027 0 : result->day++;
3028 : }
3029 :
3030 8342 : PG_RETURN_INTERVAL_P(result);
3031 : }
3032 :
3033 : /*
3034 : * interval_justify_days()
3035 : *
3036 : * Adjust interval so 'day' contains less than 30 days, adding
3037 : * the excess to 'month'.
3038 : */
3039 : Datum
3040 2004 : interval_justify_days(PG_FUNCTION_ARGS)
3041 : {
3042 2004 : Interval *span = PG_GETARG_INTERVAL_P(0);
3043 : Interval *result;
3044 : int32 wholemonth;
3045 :
3046 2004 : result = (Interval *) palloc(sizeof(Interval));
3047 2004 : result->month = span->month;
3048 2004 : result->day = span->day;
3049 2004 : result->time = span->time;
3050 :
3051 : /* do nothing for infinite intervals */
3052 2004 : if (INTERVAL_NOT_FINITE(result))
3053 12 : PG_RETURN_INTERVAL_P(result);
3054 :
3055 1992 : wholemonth = result->day / DAYS_PER_MONTH;
3056 1992 : result->day -= wholemonth * DAYS_PER_MONTH;
3057 1992 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
3058 6 : ereport(ERROR,
3059 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3060 : errmsg("interval out of range")));
3061 :
3062 1986 : if (result->month > 0 && result->day < 0)
3063 : {
3064 0 : result->day += DAYS_PER_MONTH;
3065 0 : result->month--;
3066 : }
3067 1986 : else if (result->month < 0 && result->day > 0)
3068 : {
3069 0 : result->day -= DAYS_PER_MONTH;
3070 0 : result->month++;
3071 : }
3072 :
3073 1986 : PG_RETURN_INTERVAL_P(result);
3074 : }
3075 :
3076 : /* timestamp_pl_interval()
3077 : * Add an interval to a timestamp data type.
3078 : * Note that interval has provisions for qualitative year/month and day
3079 : * units, so try to do the right thing with them.
3080 : * To add a month, increment the month, and use the same day of month.
3081 : * Then, if the next month has fewer days, set the day of month
3082 : * to the last day of month.
3083 : * To add a day, increment the mday, and use the same time of day.
3084 : * Lastly, add in the "quantitative time".
3085 : */
3086 : Datum
3087 9782 : timestamp_pl_interval(PG_FUNCTION_ARGS)
3088 : {
3089 9782 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3090 9782 : Interval *span = PG_GETARG_INTERVAL_P(1);
3091 : Timestamp result;
3092 :
3093 : /*
3094 : * Handle infinities.
3095 : *
3096 : * We treat anything that amounts to "infinity - infinity" as an error,
3097 : * since the timestamp type has nothing equivalent to NaN.
3098 : */
3099 9782 : if (INTERVAL_IS_NOBEGIN(span))
3100 : {
3101 276 : if (TIMESTAMP_IS_NOEND(timestamp))
3102 24 : ereport(ERROR,
3103 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3104 : errmsg("timestamp out of range")));
3105 : else
3106 252 : TIMESTAMP_NOBEGIN(result);
3107 : }
3108 9506 : else if (INTERVAL_IS_NOEND(span))
3109 : {
3110 204 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
3111 24 : ereport(ERROR,
3112 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3113 : errmsg("timestamp out of range")));
3114 : else
3115 180 : TIMESTAMP_NOEND(result);
3116 : }
3117 9302 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3118 114 : result = timestamp;
3119 : else
3120 : {
3121 9188 : if (span->month != 0)
3122 : {
3123 : struct pg_tm tt,
3124 2628 : *tm = &tt;
3125 : fsec_t fsec;
3126 :
3127 2628 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3128 0 : ereport(ERROR,
3129 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3130 : errmsg("timestamp out of range")));
3131 :
3132 2628 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3133 0 : ereport(ERROR,
3134 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3135 : errmsg("timestamp out of range")));
3136 2628 : if (tm->tm_mon > MONTHS_PER_YEAR)
3137 : {
3138 1398 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3139 1398 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3140 : }
3141 1230 : else if (tm->tm_mon < 1)
3142 : {
3143 1170 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3144 1170 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3145 : }
3146 :
3147 : /* adjust for end of month boundary problems... */
3148 2628 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3149 12 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3150 :
3151 2628 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3152 0 : ereport(ERROR,
3153 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3154 : errmsg("timestamp out of range")));
3155 : }
3156 :
3157 9188 : if (span->day != 0)
3158 : {
3159 : struct pg_tm tt,
3160 3084 : *tm = &tt;
3161 : fsec_t fsec;
3162 : int julian;
3163 :
3164 3084 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3165 0 : ereport(ERROR,
3166 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3167 : errmsg("timestamp out of range")));
3168 :
3169 : /*
3170 : * Add days by converting to and from Julian. We need an overflow
3171 : * check here since j2date expects a non-negative integer input.
3172 : */
3173 3084 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3174 3084 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3175 3084 : julian < 0)
3176 6 : ereport(ERROR,
3177 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3178 : errmsg("timestamp out of range")));
3179 3078 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3180 :
3181 3078 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3182 0 : ereport(ERROR,
3183 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3184 : errmsg("timestamp out of range")));
3185 : }
3186 :
3187 9182 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3188 6 : ereport(ERROR,
3189 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3190 : errmsg("timestamp out of range")));
3191 :
3192 9176 : if (!IS_VALID_TIMESTAMP(timestamp))
3193 0 : ereport(ERROR,
3194 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3195 : errmsg("timestamp out of range")));
3196 :
3197 9176 : result = timestamp;
3198 : }
3199 :
3200 9722 : PG_RETURN_TIMESTAMP(result);
3201 : }
3202 :
3203 : Datum
3204 2172 : timestamp_mi_interval(PG_FUNCTION_ARGS)
3205 : {
3206 2172 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3207 2172 : Interval *span = PG_GETARG_INTERVAL_P(1);
3208 : Interval tspan;
3209 :
3210 2172 : interval_um_internal(span, &tspan);
3211 :
3212 2172 : return DirectFunctionCall2(timestamp_pl_interval,
3213 : TimestampGetDatum(timestamp),
3214 : PointerGetDatum(&tspan));
3215 : }
3216 :
3217 :
3218 : /* timestamptz_pl_interval_internal()
3219 : * Add an interval to a timestamptz, in the given (or session) timezone.
3220 : *
3221 : * Note that interval has provisions for qualitative year/month and day
3222 : * units, so try to do the right thing with them.
3223 : * To add a month, increment the month, and use the same day of month.
3224 : * Then, if the next month has fewer days, set the day of month
3225 : * to the last day of month.
3226 : * To add a day, increment the mday, and use the same time of day.
3227 : * Lastly, add in the "quantitative time".
3228 : */
3229 : static TimestampTz
3230 151990 : timestamptz_pl_interval_internal(TimestampTz timestamp,
3231 : Interval *span,
3232 : pg_tz *attimezone)
3233 : {
3234 : TimestampTz result;
3235 : int tz;
3236 :
3237 : /*
3238 : * Handle infinities.
3239 : *
3240 : * We treat anything that amounts to "infinity - infinity" as an error,
3241 : * since the timestamptz type has nothing equivalent to NaN.
3242 : */
3243 151990 : if (INTERVAL_IS_NOBEGIN(span))
3244 : {
3245 432 : if (TIMESTAMP_IS_NOEND(timestamp))
3246 12 : ereport(ERROR,
3247 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3248 : errmsg("timestamp out of range")));
3249 : else
3250 420 : TIMESTAMP_NOBEGIN(result);
3251 : }
3252 151558 : else if (INTERVAL_IS_NOEND(span))
3253 : {
3254 360 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
3255 12 : ereport(ERROR,
3256 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3257 : errmsg("timestamp out of range")));
3258 : else
3259 348 : TIMESTAMP_NOEND(result);
3260 : }
3261 151198 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3262 120 : result = timestamp;
3263 : else
3264 : {
3265 : /* Use session timezone if caller asks for default */
3266 151078 : if (attimezone == NULL)
3267 88470 : attimezone = session_timezone;
3268 :
3269 151078 : if (span->month != 0)
3270 : {
3271 : struct pg_tm tt,
3272 55848 : *tm = &tt;
3273 : fsec_t fsec;
3274 :
3275 55848 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3276 0 : ereport(ERROR,
3277 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3278 : errmsg("timestamp out of range")));
3279 :
3280 55848 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3281 0 : ereport(ERROR,
3282 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3283 : errmsg("timestamp out of range")));
3284 55848 : if (tm->tm_mon > MONTHS_PER_YEAR)
3285 : {
3286 54072 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3287 54072 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3288 : }
3289 1776 : else if (tm->tm_mon < 1)
3290 : {
3291 1350 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3292 1350 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3293 : }
3294 :
3295 : /* adjust for end of month boundary problems... */
3296 55848 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3297 54 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3298 :
3299 55848 : tz = DetermineTimeZoneOffset(tm, attimezone);
3300 :
3301 55848 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3302 0 : ereport(ERROR,
3303 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3304 : errmsg("timestamp out of range")));
3305 : }
3306 :
3307 151078 : if (span->day != 0)
3308 : {
3309 : struct pg_tm tt,
3310 3654 : *tm = &tt;
3311 : fsec_t fsec;
3312 : int julian;
3313 :
3314 3654 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3315 0 : ereport(ERROR,
3316 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3317 : errmsg("timestamp out of range")));
3318 :
3319 : /*
3320 : * Add days by converting to and from Julian. We need an overflow
3321 : * check here since j2date expects a non-negative integer input.
3322 : * In practice though, it will give correct answers for small
3323 : * negative Julian dates; we should allow -1 to avoid
3324 : * timezone-dependent failures, as discussed in timestamp.h.
3325 : */
3326 3654 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3327 3654 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3328 3654 : julian < -1)
3329 6 : ereport(ERROR,
3330 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3331 : errmsg("timestamp out of range")));
3332 3648 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3333 :
3334 3648 : tz = DetermineTimeZoneOffset(tm, attimezone);
3335 :
3336 3648 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3337 0 : ereport(ERROR,
3338 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3339 : errmsg("timestamp out of range")));
3340 : }
3341 :
3342 151072 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3343 6 : ereport(ERROR,
3344 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3345 : errmsg("timestamp out of range")));
3346 :
3347 151066 : if (!IS_VALID_TIMESTAMP(timestamp))
3348 0 : ereport(ERROR,
3349 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3350 : errmsg("timestamp out of range")));
3351 :
3352 151066 : result = timestamp;
3353 : }
3354 :
3355 151954 : return result;
3356 : }
3357 :
3358 : /* timestamptz_mi_interval_internal()
3359 : * As above, but subtract the interval.
3360 : */
3361 : static TimestampTz
3362 2118 : timestamptz_mi_interval_internal(TimestampTz timestamp,
3363 : Interval *span,
3364 : pg_tz *attimezone)
3365 : {
3366 : Interval tspan;
3367 :
3368 2118 : interval_um_internal(span, &tspan);
3369 :
3370 2118 : return timestamptz_pl_interval_internal(timestamp, &tspan, attimezone);
3371 : }
3372 :
3373 : /* timestamptz_pl_interval()
3374 : * Add an interval to a timestamptz, in the session timezone.
3375 : */
3376 : Datum
3377 86856 : timestamptz_pl_interval(PG_FUNCTION_ARGS)
3378 : {
3379 86856 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3380 86856 : Interval *span = PG_GETARG_INTERVAL_P(1);
3381 :
3382 86856 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, NULL));
3383 : }
3384 :
3385 : Datum
3386 1632 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
3387 : {
3388 1632 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3389 1632 : Interval *span = PG_GETARG_INTERVAL_P(1);
3390 :
3391 1632 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, NULL));
3392 : }
3393 :
3394 : /* timestamptz_pl_interval_at_zone()
3395 : * Add an interval to a timestamptz, in the specified timezone.
3396 : */
3397 : Datum
3398 6 : timestamptz_pl_interval_at_zone(PG_FUNCTION_ARGS)
3399 : {
3400 6 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3401 6 : Interval *span = PG_GETARG_INTERVAL_P(1);
3402 6 : text *zone = PG_GETARG_TEXT_PP(2);
3403 6 : pg_tz *attimezone = lookup_timezone(zone);
3404 :
3405 6 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, attimezone));
3406 : }
3407 :
3408 : Datum
3409 6 : timestamptz_mi_interval_at_zone(PG_FUNCTION_ARGS)
3410 : {
3411 6 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3412 6 : Interval *span = PG_GETARG_INTERVAL_P(1);
3413 6 : text *zone = PG_GETARG_TEXT_PP(2);
3414 6 : pg_tz *attimezone = lookup_timezone(zone);
3415 :
3416 6 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, attimezone));
3417 : }
3418 :
3419 : /* interval_um_internal()
3420 : * Negate an interval.
3421 : */
3422 : static void
3423 8040 : interval_um_internal(const Interval *interval, Interval *result)
3424 : {
3425 8040 : if (INTERVAL_IS_NOBEGIN(interval))
3426 270 : INTERVAL_NOEND(result);
3427 7770 : else if (INTERVAL_IS_NOEND(interval))
3428 678 : INTERVAL_NOBEGIN(result);
3429 : else
3430 : {
3431 : /* Negate each field, guarding against overflow */
3432 14178 : if (pg_sub_s64_overflow(INT64CONST(0), interval->time, &result->time) ||
3433 14166 : pg_sub_s32_overflow(0, interval->day, &result->day) ||
3434 7080 : pg_sub_s32_overflow(0, interval->month, &result->month) ||
3435 7074 : INTERVAL_NOT_FINITE(result))
3436 30 : ereport(ERROR,
3437 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3438 : errmsg("interval out of range")));
3439 : }
3440 8010 : }
3441 :
3442 : Datum
3443 3714 : interval_um(PG_FUNCTION_ARGS)
3444 : {
3445 3714 : Interval *interval = PG_GETARG_INTERVAL_P(0);
3446 : Interval *result;
3447 :
3448 3714 : result = (Interval *) palloc(sizeof(Interval));
3449 3714 : interval_um_internal(interval, result);
3450 :
3451 3684 : PG_RETURN_INTERVAL_P(result);
3452 : }
3453 :
3454 :
3455 : Datum
3456 0 : interval_smaller(PG_FUNCTION_ARGS)
3457 : {
3458 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3459 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3460 : Interval *result;
3461 :
3462 : /* use interval_cmp_internal to be sure this agrees with comparisons */
3463 0 : if (interval_cmp_internal(interval1, interval2) < 0)
3464 0 : result = interval1;
3465 : else
3466 0 : result = interval2;
3467 0 : PG_RETURN_INTERVAL_P(result);
3468 : }
3469 :
3470 : Datum
3471 0 : interval_larger(PG_FUNCTION_ARGS)
3472 : {
3473 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3474 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3475 : Interval *result;
3476 :
3477 0 : if (interval_cmp_internal(interval1, interval2) > 0)
3478 0 : result = interval1;
3479 : else
3480 0 : result = interval2;
3481 0 : PG_RETURN_INTERVAL_P(result);
3482 : }
3483 :
3484 : static void
3485 528 : finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result)
3486 : {
3487 : Assert(!INTERVAL_NOT_FINITE(span1));
3488 : Assert(!INTERVAL_NOT_FINITE(span2));
3489 :
3490 1056 : if (pg_add_s32_overflow(span1->month, span2->month, &result->month) ||
3491 1056 : pg_add_s32_overflow(span1->day, span2->day, &result->day) ||
3492 528 : pg_add_s64_overflow(span1->time, span2->time, &result->time) ||
3493 528 : INTERVAL_NOT_FINITE(result))
3494 12 : ereport(ERROR,
3495 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3496 : errmsg("interval out of range")));
3497 516 : }
3498 :
3499 : Datum
3500 558 : interval_pl(PG_FUNCTION_ARGS)
3501 : {
3502 558 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3503 558 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3504 : Interval *result;
3505 :
3506 558 : result = (Interval *) palloc(sizeof(Interval));
3507 :
3508 : /*
3509 : * Handle infinities.
3510 : *
3511 : * We treat anything that amounts to "infinity - infinity" as an error,
3512 : * since the interval type has nothing equivalent to NaN.
3513 : */
3514 558 : if (INTERVAL_IS_NOBEGIN(span1))
3515 : {
3516 54 : if (INTERVAL_IS_NOEND(span2))
3517 6 : ereport(ERROR,
3518 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3519 : errmsg("interval out of range")));
3520 : else
3521 48 : INTERVAL_NOBEGIN(result);
3522 : }
3523 504 : else if (INTERVAL_IS_NOEND(span1))
3524 : {
3525 42 : if (INTERVAL_IS_NOBEGIN(span2))
3526 6 : ereport(ERROR,
3527 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3528 : errmsg("interval out of range")));
3529 : else
3530 36 : INTERVAL_NOEND(result);
3531 : }
3532 462 : else if (INTERVAL_NOT_FINITE(span2))
3533 138 : memcpy(result, span2, sizeof(Interval));
3534 : else
3535 324 : finite_interval_pl(span1, span2, result);
3536 :
3537 534 : PG_RETURN_INTERVAL_P(result);
3538 : }
3539 :
3540 : static void
3541 1548 : finite_interval_mi(const Interval *span1, const Interval *span2, Interval *result)
3542 : {
3543 : Assert(!INTERVAL_NOT_FINITE(span1));
3544 : Assert(!INTERVAL_NOT_FINITE(span2));
3545 :
3546 3096 : if (pg_sub_s32_overflow(span1->month, span2->month, &result->month) ||
3547 3096 : pg_sub_s32_overflow(span1->day, span2->day, &result->day) ||
3548 1548 : pg_sub_s64_overflow(span1->time, span2->time, &result->time) ||
3549 1548 : INTERVAL_NOT_FINITE(result))
3550 12 : ereport(ERROR,
3551 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3552 : errmsg("interval out of range")));
3553 1536 : }
3554 :
3555 : Datum
3556 1794 : interval_mi(PG_FUNCTION_ARGS)
3557 : {
3558 1794 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3559 1794 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3560 : Interval *result;
3561 :
3562 1794 : result = (Interval *) palloc(sizeof(Interval));
3563 :
3564 : /*
3565 : * Handle infinities.
3566 : *
3567 : * We treat anything that amounts to "infinity - infinity" as an error,
3568 : * since the interval type has nothing equivalent to NaN.
3569 : */
3570 1794 : if (INTERVAL_IS_NOBEGIN(span1))
3571 : {
3572 54 : if (INTERVAL_IS_NOBEGIN(span2))
3573 6 : ereport(ERROR,
3574 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3575 : errmsg("interval out of range")));
3576 : else
3577 48 : INTERVAL_NOBEGIN(result);
3578 : }
3579 1740 : else if (INTERVAL_IS_NOEND(span1))
3580 : {
3581 48 : if (INTERVAL_IS_NOEND(span2))
3582 6 : ereport(ERROR,
3583 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3584 : errmsg("interval out of range")));
3585 : else
3586 42 : INTERVAL_NOEND(result);
3587 : }
3588 1692 : else if (INTERVAL_IS_NOBEGIN(span2))
3589 6 : INTERVAL_NOEND(result);
3590 1686 : else if (INTERVAL_IS_NOEND(span2))
3591 186 : INTERVAL_NOBEGIN(result);
3592 : else
3593 1500 : finite_interval_mi(span1, span2, result);
3594 :
3595 1770 : PG_RETURN_INTERVAL_P(result);
3596 : }
3597 :
3598 : /*
3599 : * There is no interval_abs(): it is unclear what value to return:
3600 : * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3601 : * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3602 : */
3603 :
3604 : Datum
3605 11652 : interval_mul(PG_FUNCTION_ARGS)
3606 : {
3607 11652 : Interval *span = PG_GETARG_INTERVAL_P(0);
3608 11652 : float8 factor = PG_GETARG_FLOAT8(1);
3609 : double month_remainder_days,
3610 : sec_remainder,
3611 : result_double;
3612 11652 : int32 orig_month = span->month,
3613 11652 : orig_day = span->day;
3614 : Interval *result;
3615 :
3616 11652 : result = (Interval *) palloc(sizeof(Interval));
3617 :
3618 : /*
3619 : * Handle NaN and infinities.
3620 : *
3621 : * We treat "0 * infinity" and "infinity * 0" as errors, since the
3622 : * interval type has nothing equivalent to NaN.
3623 : */
3624 11652 : if (isnan(factor))
3625 12 : goto out_of_range;
3626 :
3627 11640 : if (INTERVAL_NOT_FINITE(span))
3628 : {
3629 60 : if (factor == 0.0)
3630 12 : goto out_of_range;
3631 :
3632 48 : if (factor < 0.0)
3633 24 : interval_um_internal(span, result);
3634 : else
3635 24 : memcpy(result, span, sizeof(Interval));
3636 :
3637 48 : PG_RETURN_INTERVAL_P(result);
3638 : }
3639 11580 : if (isinf(factor))
3640 : {
3641 24 : int isign = interval_sign(span);
3642 :
3643 24 : if (isign == 0)
3644 12 : goto out_of_range;
3645 :
3646 12 : if (factor * isign < 0)
3647 6 : INTERVAL_NOBEGIN(result);
3648 : else
3649 6 : INTERVAL_NOEND(result);
3650 :
3651 12 : PG_RETURN_INTERVAL_P(result);
3652 : }
3653 :
3654 11556 : result_double = span->month * factor;
3655 11556 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3656 6 : goto out_of_range;
3657 11550 : result->month = (int32) result_double;
3658 :
3659 11550 : result_double = span->day * factor;
3660 11550 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3661 6 : goto out_of_range;
3662 11544 : result->day = (int32) result_double;
3663 :
3664 : /*
3665 : * The above correctly handles the whole-number part of the month and day
3666 : * products, but we have to do something with any fractional part
3667 : * resulting when the factor is non-integral. We cascade the fractions
3668 : * down to lower units using the conversion factors DAYS_PER_MONTH and
3669 : * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
3670 : * so by the representation. The user can choose to cascade up later,
3671 : * using justify_hours and/or justify_days.
3672 : */
3673 :
3674 : /*
3675 : * Fractional months full days into days.
3676 : *
3677 : * Floating point calculation are inherently imprecise, so these
3678 : * calculations are crafted to produce the most reliable result possible.
3679 : * TSROUND() is needed to more accurately produce whole numbers where
3680 : * appropriate.
3681 : */
3682 11544 : month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
3683 11544 : month_remainder_days = TSROUND(month_remainder_days);
3684 11544 : sec_remainder = (orig_day * factor - result->day +
3685 11544 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3686 11544 : sec_remainder = TSROUND(sec_remainder);
3687 :
3688 : /*
3689 : * Might have 24:00:00 hours due to rounding, or >24 hours because of time
3690 : * cascade from months and days. It might still be >24 if the combination
3691 : * of cascade and the seconds factor operation itself.
3692 : */
3693 11544 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3694 : {
3695 0 : if (pg_add_s32_overflow(result->day,
3696 0 : (int) (sec_remainder / SECS_PER_DAY),
3697 : &result->day))
3698 0 : goto out_of_range;
3699 0 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3700 : }
3701 :
3702 : /* cascade units down */
3703 11544 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3704 : &result->day))
3705 6 : goto out_of_range;
3706 11538 : result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
3707 11538 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3708 6 : goto out_of_range;
3709 11532 : result->time = (int64) result_double;
3710 :
3711 11532 : if (INTERVAL_NOT_FINITE(result))
3712 6 : goto out_of_range;
3713 :
3714 11526 : PG_RETURN_INTERVAL_P(result);
3715 :
3716 66 : out_of_range:
3717 66 : ereport(ERROR,
3718 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3719 : errmsg("interval out of range"));
3720 :
3721 : PG_RETURN_NULL(); /* keep compiler quiet */
3722 : }
3723 :
3724 : Datum
3725 11430 : mul_d_interval(PG_FUNCTION_ARGS)
3726 : {
3727 : /* Args are float8 and Interval *, but leave them as generic Datum */
3728 11430 : Datum factor = PG_GETARG_DATUM(0);
3729 11430 : Datum span = PG_GETARG_DATUM(1);
3730 :
3731 11430 : return DirectFunctionCall2(interval_mul, span, factor);
3732 : }
3733 :
3734 : Datum
3735 222 : interval_div(PG_FUNCTION_ARGS)
3736 : {
3737 222 : Interval *span = PG_GETARG_INTERVAL_P(0);
3738 222 : float8 factor = PG_GETARG_FLOAT8(1);
3739 : double month_remainder_days,
3740 : sec_remainder,
3741 : result_double;
3742 222 : int32 orig_month = span->month,
3743 222 : orig_day = span->day;
3744 : Interval *result;
3745 :
3746 222 : result = (Interval *) palloc(sizeof(Interval));
3747 :
3748 222 : if (factor == 0.0)
3749 0 : ereport(ERROR,
3750 : (errcode(ERRCODE_DIVISION_BY_ZERO),
3751 : errmsg("division by zero")));
3752 :
3753 : /*
3754 : * Handle NaN and infinities.
3755 : *
3756 : * We treat "infinity / infinity" as an error, since the interval type has
3757 : * nothing equivalent to NaN. Otherwise, dividing by infinity is handled
3758 : * by the regular division code, causing all fields to be set to zero.
3759 : */
3760 222 : if (isnan(factor))
3761 12 : goto out_of_range;
3762 :
3763 210 : if (INTERVAL_NOT_FINITE(span))
3764 : {
3765 48 : if (isinf(factor))
3766 24 : goto out_of_range;
3767 :
3768 24 : if (factor < 0.0)
3769 12 : interval_um_internal(span, result);
3770 : else
3771 12 : memcpy(result, span, sizeof(Interval));
3772 :
3773 24 : PG_RETURN_INTERVAL_P(result);
3774 : }
3775 :
3776 162 : result_double = span->month / factor;
3777 162 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3778 6 : goto out_of_range;
3779 156 : result->month = (int32) result_double;
3780 :
3781 156 : result_double = span->day / factor;
3782 156 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3783 6 : goto out_of_range;
3784 150 : result->day = (int32) result_double;
3785 :
3786 : /*
3787 : * Fractional months full days into days. See comment in interval_mul().
3788 : */
3789 150 : month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
3790 150 : month_remainder_days = TSROUND(month_remainder_days);
3791 150 : sec_remainder = (orig_day / factor - result->day +
3792 150 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3793 150 : sec_remainder = TSROUND(sec_remainder);
3794 150 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3795 : {
3796 6 : if (pg_add_s32_overflow(result->day,
3797 6 : (int) (sec_remainder / SECS_PER_DAY),
3798 : &result->day))
3799 0 : goto out_of_range;
3800 6 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3801 : }
3802 :
3803 : /* cascade units down */
3804 150 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3805 : &result->day))
3806 0 : goto out_of_range;
3807 150 : result_double = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
3808 150 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3809 6 : goto out_of_range;
3810 144 : result->time = (int64) result_double;
3811 :
3812 144 : if (INTERVAL_NOT_FINITE(result))
3813 6 : goto out_of_range;
3814 :
3815 138 : PG_RETURN_INTERVAL_P(result);
3816 :
3817 60 : out_of_range:
3818 60 : ereport(ERROR,
3819 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3820 : errmsg("interval out of range"));
3821 :
3822 : PG_RETURN_NULL(); /* keep compiler quiet */
3823 : }
3824 :
3825 :
3826 : /*
3827 : * in_range support functions for timestamps and intervals.
3828 : *
3829 : * Per SQL spec, we support these with interval as the offset type.
3830 : * The spec's restriction that the offset not be negative is a bit hard to
3831 : * decipher for intervals, but we choose to interpret it the same as our
3832 : * interval comparison operators would.
3833 : */
3834 :
3835 : Datum
3836 1134 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
3837 : {
3838 1134 : TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
3839 1134 : TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
3840 1134 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3841 1134 : bool sub = PG_GETARG_BOOL(3);
3842 1134 : bool less = PG_GETARG_BOOL(4);
3843 : TimestampTz sum;
3844 :
3845 1134 : if (interval_sign(offset) < 0)
3846 12 : ereport(ERROR,
3847 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3848 : errmsg("invalid preceding or following size in window function")));
3849 :
3850 : /*
3851 : * Deal with cases where both base and offset are infinite, and computing
3852 : * base +/- offset would cause an error. As for float and numeric types,
3853 : * we assume that all values infinitely precede +infinity and infinitely
3854 : * follow -infinity. See in_range_float8_float8() for reasoning.
3855 : */
3856 1122 : if (INTERVAL_IS_NOEND(offset) &&
3857 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3858 228 : PG_RETURN_BOOL(true);
3859 :
3860 : /* We don't currently bother to avoid overflow hazards here */
3861 894 : if (sub)
3862 480 : sum = timestamptz_mi_interval_internal(base, offset, NULL);
3863 : else
3864 414 : sum = timestamptz_pl_interval_internal(base, offset, NULL);
3865 :
3866 894 : if (less)
3867 354 : PG_RETURN_BOOL(val <= sum);
3868 : else
3869 540 : PG_RETURN_BOOL(val >= sum);
3870 : }
3871 :
3872 : Datum
3873 2466 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
3874 : {
3875 2466 : Timestamp val = PG_GETARG_TIMESTAMP(0);
3876 2466 : Timestamp base = PG_GETARG_TIMESTAMP(1);
3877 2466 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3878 2466 : bool sub = PG_GETARG_BOOL(3);
3879 2466 : bool less = PG_GETARG_BOOL(4);
3880 : Timestamp sum;
3881 :
3882 2466 : if (interval_sign(offset) < 0)
3883 18 : ereport(ERROR,
3884 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3885 : errmsg("invalid preceding or following size in window function")));
3886 :
3887 : /*
3888 : * Deal with cases where both base and offset are infinite, and computing
3889 : * base +/- offset would cause an error. As for float and numeric types,
3890 : * we assume that all values infinitely precede +infinity and infinitely
3891 : * follow -infinity. See in_range_float8_float8() for reasoning.
3892 : */
3893 2448 : if (INTERVAL_IS_NOEND(offset) &&
3894 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3895 228 : PG_RETURN_BOOL(true);
3896 :
3897 : /* We don't currently bother to avoid overflow hazards here */
3898 2220 : if (sub)
3899 1032 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
3900 : TimestampGetDatum(base),
3901 : IntervalPGetDatum(offset)));
3902 : else
3903 1188 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
3904 : TimestampGetDatum(base),
3905 : IntervalPGetDatum(offset)));
3906 :
3907 2220 : if (less)
3908 1206 : PG_RETURN_BOOL(val <= sum);
3909 : else
3910 1014 : PG_RETURN_BOOL(val >= sum);
3911 : }
3912 :
3913 : Datum
3914 1128 : in_range_interval_interval(PG_FUNCTION_ARGS)
3915 : {
3916 1128 : Interval *val = PG_GETARG_INTERVAL_P(0);
3917 1128 : Interval *base = PG_GETARG_INTERVAL_P(1);
3918 1128 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3919 1128 : bool sub = PG_GETARG_BOOL(3);
3920 1128 : bool less = PG_GETARG_BOOL(4);
3921 : Interval *sum;
3922 :
3923 1128 : if (interval_sign(offset) < 0)
3924 12 : ereport(ERROR,
3925 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3926 : errmsg("invalid preceding or following size in window function")));
3927 :
3928 : /*
3929 : * Deal with cases where both base and offset are infinite, and computing
3930 : * base +/- offset would cause an error. As for float and numeric types,
3931 : * we assume that all values infinitely precede +infinity and infinitely
3932 : * follow -infinity. See in_range_float8_float8() for reasoning.
3933 : */
3934 1680 : if (INTERVAL_IS_NOEND(offset) &&
3935 564 : (sub ? INTERVAL_IS_NOEND(base) : INTERVAL_IS_NOBEGIN(base)))
3936 228 : PG_RETURN_BOOL(true);
3937 :
3938 : /* We don't currently bother to avoid overflow hazards here */
3939 888 : if (sub)
3940 480 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
3941 : IntervalPGetDatum(base),
3942 : IntervalPGetDatum(offset)));
3943 : else
3944 408 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
3945 : IntervalPGetDatum(base),
3946 : IntervalPGetDatum(offset)));
3947 :
3948 888 : if (less)
3949 348 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3950 : else
3951 540 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3952 : }
3953 :
3954 :
3955 : /*
3956 : * Prepare state data for an interval aggregate function, that needs to compute
3957 : * sum and count, in the aggregate's memory context.
3958 : *
3959 : * The function is used when the state data needs to be allocated in aggregate's
3960 : * context. When the state data needs to be allocated in the current memory
3961 : * context, we use palloc0 directly e.g. interval_avg_deserialize().
3962 : */
3963 : static IntervalAggState *
3964 54 : makeIntervalAggState(FunctionCallInfo fcinfo)
3965 : {
3966 : IntervalAggState *state;
3967 : MemoryContext agg_context;
3968 : MemoryContext old_context;
3969 :
3970 54 : if (!AggCheckCallContext(fcinfo, &agg_context))
3971 0 : elog(ERROR, "aggregate function called in non-aggregate context");
3972 :
3973 54 : old_context = MemoryContextSwitchTo(agg_context);
3974 :
3975 54 : state = (IntervalAggState *) palloc0(sizeof(IntervalAggState));
3976 :
3977 54 : MemoryContextSwitchTo(old_context);
3978 :
3979 54 : return state;
3980 : }
3981 :
3982 : /*
3983 : * Accumulate a new input value for interval aggregate functions.
3984 : */
3985 : static void
3986 324 : do_interval_accum(IntervalAggState *state, Interval *newval)
3987 : {
3988 : /* Infinite inputs are counted separately, and do not affect "N" */
3989 324 : if (INTERVAL_IS_NOBEGIN(newval))
3990 : {
3991 60 : state->nInfcount++;
3992 60 : return;
3993 : }
3994 :
3995 264 : if (INTERVAL_IS_NOEND(newval))
3996 : {
3997 60 : state->pInfcount++;
3998 60 : return;
3999 : }
4000 :
4001 204 : finite_interval_pl(&state->sumX, newval, &state->sumX);
4002 204 : state->N++;
4003 : }
4004 :
4005 : /*
4006 : * Remove the given interval value from the aggregated state.
4007 : */
4008 : static void
4009 204 : do_interval_discard(IntervalAggState *state, Interval *newval)
4010 : {
4011 : /* Infinite inputs are counted separately, and do not affect "N" */
4012 204 : if (INTERVAL_IS_NOBEGIN(newval))
4013 : {
4014 24 : state->nInfcount--;
4015 24 : return;
4016 : }
4017 :
4018 180 : if (INTERVAL_IS_NOEND(newval))
4019 : {
4020 48 : state->pInfcount--;
4021 48 : return;
4022 : }
4023 :
4024 : /* Handle the to-be-discarded finite value. */
4025 132 : state->N--;
4026 132 : if (state->N > 0)
4027 48 : finite_interval_mi(&state->sumX, newval, &state->sumX);
4028 : else
4029 : {
4030 : /* All values discarded, reset the state */
4031 : Assert(state->N == 0);
4032 84 : memset(&state->sumX, 0, sizeof(state->sumX));
4033 : }
4034 : }
4035 :
4036 : /*
4037 : * Transition function for sum() and avg() interval aggregates.
4038 : */
4039 : Datum
4040 408 : interval_avg_accum(PG_FUNCTION_ARGS)
4041 : {
4042 : IntervalAggState *state;
4043 :
4044 408 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4045 :
4046 : /* Create the state data on the first call */
4047 408 : if (state == NULL)
4048 54 : state = makeIntervalAggState(fcinfo);
4049 :
4050 408 : if (!PG_ARGISNULL(1))
4051 324 : do_interval_accum(state, PG_GETARG_INTERVAL_P(1));
4052 :
4053 408 : PG_RETURN_POINTER(state);
4054 : }
4055 :
4056 : /*
4057 : * Combine function for sum() and avg() interval aggregates.
4058 : *
4059 : * Combine the given internal aggregate states and place the combination in
4060 : * the first argument.
4061 : */
4062 : Datum
4063 0 : interval_avg_combine(PG_FUNCTION_ARGS)
4064 : {
4065 : IntervalAggState *state1;
4066 : IntervalAggState *state2;
4067 :
4068 0 : state1 = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4069 0 : state2 = PG_ARGISNULL(1) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(1);
4070 :
4071 0 : if (state2 == NULL)
4072 0 : PG_RETURN_POINTER(state1);
4073 :
4074 0 : if (state1 == NULL)
4075 : {
4076 : /* manually copy all fields from state2 to state1 */
4077 0 : state1 = makeIntervalAggState(fcinfo);
4078 :
4079 0 : state1->N = state2->N;
4080 0 : state1->pInfcount = state2->pInfcount;
4081 0 : state1->nInfcount = state2->nInfcount;
4082 :
4083 0 : state1->sumX.day = state2->sumX.day;
4084 0 : state1->sumX.month = state2->sumX.month;
4085 0 : state1->sumX.time = state2->sumX.time;
4086 :
4087 0 : PG_RETURN_POINTER(state1);
4088 : }
4089 :
4090 0 : state1->N += state2->N;
4091 0 : state1->pInfcount += state2->pInfcount;
4092 0 : state1->nInfcount += state2->nInfcount;
4093 :
4094 : /* Accumulate finite interval values, if any. */
4095 0 : if (state2->N > 0)
4096 0 : finite_interval_pl(&state1->sumX, &state2->sumX, &state1->sumX);
4097 :
4098 0 : PG_RETURN_POINTER(state1);
4099 : }
4100 :
4101 : /*
4102 : * interval_avg_serialize
4103 : * Serialize IntervalAggState for interval aggregates.
4104 : */
4105 : Datum
4106 0 : interval_avg_serialize(PG_FUNCTION_ARGS)
4107 : {
4108 : IntervalAggState *state;
4109 : StringInfoData buf;
4110 : bytea *result;
4111 :
4112 : /* Ensure we disallow calling when not in aggregate context */
4113 0 : if (!AggCheckCallContext(fcinfo, NULL))
4114 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4115 :
4116 0 : state = (IntervalAggState *) PG_GETARG_POINTER(0);
4117 :
4118 0 : pq_begintypsend(&buf);
4119 :
4120 : /* N */
4121 0 : pq_sendint64(&buf, state->N);
4122 :
4123 : /* sumX */
4124 0 : pq_sendint64(&buf, state->sumX.time);
4125 0 : pq_sendint32(&buf, state->sumX.day);
4126 0 : pq_sendint32(&buf, state->sumX.month);
4127 :
4128 : /* pInfcount */
4129 0 : pq_sendint64(&buf, state->pInfcount);
4130 :
4131 : /* nInfcount */
4132 0 : pq_sendint64(&buf, state->nInfcount);
4133 :
4134 0 : result = pq_endtypsend(&buf);
4135 :
4136 0 : PG_RETURN_BYTEA_P(result);
4137 : }
4138 :
4139 : /*
4140 : * interval_avg_deserialize
4141 : * Deserialize bytea into IntervalAggState for interval aggregates.
4142 : */
4143 : Datum
4144 0 : interval_avg_deserialize(PG_FUNCTION_ARGS)
4145 : {
4146 : bytea *sstate;
4147 : IntervalAggState *result;
4148 : StringInfoData buf;
4149 :
4150 0 : if (!AggCheckCallContext(fcinfo, NULL))
4151 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4152 :
4153 0 : sstate = PG_GETARG_BYTEA_PP(0);
4154 :
4155 : /*
4156 : * Initialize a StringInfo so that we can "receive" it using the standard
4157 : * recv-function infrastructure.
4158 : */
4159 0 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
4160 0 : VARSIZE_ANY_EXHDR(sstate));
4161 :
4162 0 : result = (IntervalAggState *) palloc0(sizeof(IntervalAggState));
4163 :
4164 : /* N */
4165 0 : result->N = pq_getmsgint64(&buf);
4166 :
4167 : /* sumX */
4168 0 : result->sumX.time = pq_getmsgint64(&buf);
4169 0 : result->sumX.day = pq_getmsgint(&buf, 4);
4170 0 : result->sumX.month = pq_getmsgint(&buf, 4);
4171 :
4172 : /* pInfcount */
4173 0 : result->pInfcount = pq_getmsgint64(&buf);
4174 :
4175 : /* nInfcount */
4176 0 : result->nInfcount = pq_getmsgint64(&buf);
4177 :
4178 0 : pq_getmsgend(&buf);
4179 :
4180 0 : PG_RETURN_POINTER(result);
4181 : }
4182 :
4183 : /*
4184 : * Inverse transition function for sum() and avg() interval aggregates.
4185 : */
4186 : Datum
4187 264 : interval_avg_accum_inv(PG_FUNCTION_ARGS)
4188 : {
4189 : IntervalAggState *state;
4190 :
4191 264 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4192 :
4193 : /* Should not get here with no state */
4194 264 : if (state == NULL)
4195 0 : elog(ERROR, "interval_avg_accum_inv called with NULL state");
4196 :
4197 264 : if (!PG_ARGISNULL(1))
4198 204 : do_interval_discard(state, PG_GETARG_INTERVAL_P(1));
4199 :
4200 264 : PG_RETURN_POINTER(state);
4201 : }
4202 :
4203 : /* avg(interval) aggregate final function */
4204 : Datum
4205 168 : interval_avg(PG_FUNCTION_ARGS)
4206 : {
4207 : IntervalAggState *state;
4208 :
4209 168 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4210 :
4211 : /* If there were no non-null inputs, return NULL */
4212 168 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4213 18 : PG_RETURN_NULL();
4214 :
4215 : /*
4216 : * Aggregating infinities that all have the same sign produces infinity
4217 : * with that sign. Aggregating infinities with different signs results in
4218 : * an error.
4219 : */
4220 150 : if (state->pInfcount > 0 || state->nInfcount > 0)
4221 : {
4222 : Interval *result;
4223 :
4224 108 : if (state->pInfcount > 0 && state->nInfcount > 0)
4225 6 : ereport(ERROR,
4226 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4227 : errmsg("interval out of range")));
4228 :
4229 102 : result = (Interval *) palloc(sizeof(Interval));
4230 102 : if (state->pInfcount > 0)
4231 60 : INTERVAL_NOEND(result);
4232 : else
4233 42 : INTERVAL_NOBEGIN(result);
4234 :
4235 102 : PG_RETURN_INTERVAL_P(result);
4236 : }
4237 :
4238 42 : return DirectFunctionCall2(interval_div,
4239 : IntervalPGetDatum(&state->sumX),
4240 : Float8GetDatum((double) state->N));
4241 : }
4242 :
4243 : /* sum(interval) aggregate final function */
4244 : Datum
4245 162 : interval_sum(PG_FUNCTION_ARGS)
4246 : {
4247 : IntervalAggState *state;
4248 : Interval *result;
4249 :
4250 162 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4251 :
4252 : /* If there were no non-null inputs, return NULL */
4253 162 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4254 18 : PG_RETURN_NULL();
4255 :
4256 : /*
4257 : * Aggregating infinities that all have the same sign produces infinity
4258 : * with that sign. Aggregating infinities with different signs results in
4259 : * an error.
4260 : */
4261 144 : if (state->pInfcount > 0 && state->nInfcount > 0)
4262 6 : ereport(ERROR,
4263 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4264 : errmsg("interval out of range")));
4265 :
4266 138 : result = (Interval *) palloc(sizeof(Interval));
4267 :
4268 138 : if (state->pInfcount > 0)
4269 60 : INTERVAL_NOEND(result);
4270 78 : else if (state->nInfcount > 0)
4271 42 : INTERVAL_NOBEGIN(result);
4272 : else
4273 36 : memcpy(result, &state->sumX, sizeof(Interval));
4274 :
4275 138 : PG_RETURN_INTERVAL_P(result);
4276 : }
4277 :
4278 : /* timestamp_age()
4279 : * Calculate time difference while retaining year/month fields.
4280 : * Note that this does not result in an accurate absolute time span
4281 : * since year and month are out of context once the arithmetic
4282 : * is done.
4283 : */
4284 : Datum
4285 36 : timestamp_age(PG_FUNCTION_ARGS)
4286 : {
4287 36 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
4288 36 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
4289 : Interval *result;
4290 : fsec_t fsec1,
4291 : fsec2;
4292 : struct pg_itm tt,
4293 36 : *tm = &tt;
4294 : struct pg_tm tt1,
4295 36 : *tm1 = &tt1;
4296 : struct pg_tm tt2,
4297 36 : *tm2 = &tt2;
4298 :
4299 36 : result = (Interval *) palloc(sizeof(Interval));
4300 :
4301 : /*
4302 : * Handle infinities.
4303 : *
4304 : * We treat anything that amounts to "infinity - infinity" as an error,
4305 : * since the interval type has nothing equivalent to NaN.
4306 : */
4307 36 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4308 : {
4309 12 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4310 6 : ereport(ERROR,
4311 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4312 : errmsg("interval out of range")));
4313 : else
4314 6 : INTERVAL_NOBEGIN(result);
4315 : }
4316 24 : else if (TIMESTAMP_IS_NOEND(dt1))
4317 : {
4318 12 : if (TIMESTAMP_IS_NOEND(dt2))
4319 6 : ereport(ERROR,
4320 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4321 : errmsg("interval out of range")));
4322 : else
4323 6 : INTERVAL_NOEND(result);
4324 : }
4325 12 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4326 6 : INTERVAL_NOEND(result);
4327 6 : else if (TIMESTAMP_IS_NOEND(dt2))
4328 6 : INTERVAL_NOBEGIN(result);
4329 0 : else if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
4330 0 : timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
4331 : {
4332 : /* form the symbolic difference */
4333 0 : tm->tm_usec = fsec1 - fsec2;
4334 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4335 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4336 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4337 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4338 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4339 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4340 :
4341 : /* flip sign if necessary... */
4342 0 : if (dt1 < dt2)
4343 : {
4344 0 : tm->tm_usec = -tm->tm_usec;
4345 0 : tm->tm_sec = -tm->tm_sec;
4346 0 : tm->tm_min = -tm->tm_min;
4347 0 : tm->tm_hour = -tm->tm_hour;
4348 0 : tm->tm_mday = -tm->tm_mday;
4349 0 : tm->tm_mon = -tm->tm_mon;
4350 0 : tm->tm_year = -tm->tm_year;
4351 : }
4352 :
4353 : /* propagate any negative fields into the next higher field */
4354 0 : while (tm->tm_usec < 0)
4355 : {
4356 0 : tm->tm_usec += USECS_PER_SEC;
4357 0 : tm->tm_sec--;
4358 : }
4359 :
4360 0 : while (tm->tm_sec < 0)
4361 : {
4362 0 : tm->tm_sec += SECS_PER_MINUTE;
4363 0 : tm->tm_min--;
4364 : }
4365 :
4366 0 : while (tm->tm_min < 0)
4367 : {
4368 0 : tm->tm_min += MINS_PER_HOUR;
4369 0 : tm->tm_hour--;
4370 : }
4371 :
4372 0 : while (tm->tm_hour < 0)
4373 : {
4374 0 : tm->tm_hour += HOURS_PER_DAY;
4375 0 : tm->tm_mday--;
4376 : }
4377 :
4378 0 : while (tm->tm_mday < 0)
4379 : {
4380 0 : if (dt1 < dt2)
4381 : {
4382 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4383 0 : tm->tm_mon--;
4384 : }
4385 : else
4386 : {
4387 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4388 0 : tm->tm_mon--;
4389 : }
4390 : }
4391 :
4392 0 : while (tm->tm_mon < 0)
4393 : {
4394 0 : tm->tm_mon += MONTHS_PER_YEAR;
4395 0 : tm->tm_year--;
4396 : }
4397 :
4398 : /* recover sign if necessary... */
4399 0 : if (dt1 < dt2)
4400 : {
4401 0 : tm->tm_usec = -tm->tm_usec;
4402 0 : tm->tm_sec = -tm->tm_sec;
4403 0 : tm->tm_min = -tm->tm_min;
4404 0 : tm->tm_hour = -tm->tm_hour;
4405 0 : tm->tm_mday = -tm->tm_mday;
4406 0 : tm->tm_mon = -tm->tm_mon;
4407 0 : tm->tm_year = -tm->tm_year;
4408 : }
4409 :
4410 0 : if (itm2interval(tm, result) != 0)
4411 0 : ereport(ERROR,
4412 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4413 : errmsg("interval out of range")));
4414 : }
4415 : else
4416 0 : ereport(ERROR,
4417 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4418 : errmsg("timestamp out of range")));
4419 :
4420 24 : PG_RETURN_INTERVAL_P(result);
4421 : }
4422 :
4423 :
4424 : /* timestamptz_age()
4425 : * Calculate time difference while retaining year/month fields.
4426 : * Note that this does not result in an accurate absolute time span
4427 : * since year and month are out of context once the arithmetic
4428 : * is done.
4429 : */
4430 : Datum
4431 36 : timestamptz_age(PG_FUNCTION_ARGS)
4432 : {
4433 36 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
4434 36 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
4435 : Interval *result;
4436 : fsec_t fsec1,
4437 : fsec2;
4438 : struct pg_itm tt,
4439 36 : *tm = &tt;
4440 : struct pg_tm tt1,
4441 36 : *tm1 = &tt1;
4442 : struct pg_tm tt2,
4443 36 : *tm2 = &tt2;
4444 : int tz1;
4445 : int tz2;
4446 :
4447 36 : result = (Interval *) palloc(sizeof(Interval));
4448 :
4449 : /*
4450 : * Handle infinities.
4451 : *
4452 : * We treat anything that amounts to "infinity - infinity" as an error,
4453 : * since the interval type has nothing equivalent to NaN.
4454 : */
4455 36 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4456 : {
4457 12 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4458 6 : ereport(ERROR,
4459 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4460 : errmsg("interval out of range")));
4461 : else
4462 6 : INTERVAL_NOBEGIN(result);
4463 : }
4464 24 : else if (TIMESTAMP_IS_NOEND(dt1))
4465 : {
4466 12 : if (TIMESTAMP_IS_NOEND(dt2))
4467 6 : ereport(ERROR,
4468 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4469 : errmsg("interval out of range")));
4470 : else
4471 6 : INTERVAL_NOEND(result);
4472 : }
4473 12 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4474 6 : INTERVAL_NOEND(result);
4475 6 : else if (TIMESTAMP_IS_NOEND(dt2))
4476 6 : INTERVAL_NOBEGIN(result);
4477 0 : else if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
4478 0 : timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
4479 : {
4480 : /* form the symbolic difference */
4481 0 : tm->tm_usec = fsec1 - fsec2;
4482 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4483 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4484 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4485 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4486 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4487 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4488 :
4489 : /* flip sign if necessary... */
4490 0 : if (dt1 < dt2)
4491 : {
4492 0 : tm->tm_usec = -tm->tm_usec;
4493 0 : tm->tm_sec = -tm->tm_sec;
4494 0 : tm->tm_min = -tm->tm_min;
4495 0 : tm->tm_hour = -tm->tm_hour;
4496 0 : tm->tm_mday = -tm->tm_mday;
4497 0 : tm->tm_mon = -tm->tm_mon;
4498 0 : tm->tm_year = -tm->tm_year;
4499 : }
4500 :
4501 : /* propagate any negative fields into the next higher field */
4502 0 : while (tm->tm_usec < 0)
4503 : {
4504 0 : tm->tm_usec += USECS_PER_SEC;
4505 0 : tm->tm_sec--;
4506 : }
4507 :
4508 0 : while (tm->tm_sec < 0)
4509 : {
4510 0 : tm->tm_sec += SECS_PER_MINUTE;
4511 0 : tm->tm_min--;
4512 : }
4513 :
4514 0 : while (tm->tm_min < 0)
4515 : {
4516 0 : tm->tm_min += MINS_PER_HOUR;
4517 0 : tm->tm_hour--;
4518 : }
4519 :
4520 0 : while (tm->tm_hour < 0)
4521 : {
4522 0 : tm->tm_hour += HOURS_PER_DAY;
4523 0 : tm->tm_mday--;
4524 : }
4525 :
4526 0 : while (tm->tm_mday < 0)
4527 : {
4528 0 : if (dt1 < dt2)
4529 : {
4530 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4531 0 : tm->tm_mon--;
4532 : }
4533 : else
4534 : {
4535 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4536 0 : tm->tm_mon--;
4537 : }
4538 : }
4539 :
4540 0 : while (tm->tm_mon < 0)
4541 : {
4542 0 : tm->tm_mon += MONTHS_PER_YEAR;
4543 0 : tm->tm_year--;
4544 : }
4545 :
4546 : /*
4547 : * Note: we deliberately ignore any difference between tz1 and tz2.
4548 : */
4549 :
4550 : /* recover sign if necessary... */
4551 0 : if (dt1 < dt2)
4552 : {
4553 0 : tm->tm_usec = -tm->tm_usec;
4554 0 : tm->tm_sec = -tm->tm_sec;
4555 0 : tm->tm_min = -tm->tm_min;
4556 0 : tm->tm_hour = -tm->tm_hour;
4557 0 : tm->tm_mday = -tm->tm_mday;
4558 0 : tm->tm_mon = -tm->tm_mon;
4559 0 : tm->tm_year = -tm->tm_year;
4560 : }
4561 :
4562 0 : if (itm2interval(tm, result) != 0)
4563 0 : ereport(ERROR,
4564 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4565 : errmsg("interval out of range")));
4566 : }
4567 : else
4568 0 : ereport(ERROR,
4569 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4570 : errmsg("timestamp out of range")));
4571 :
4572 24 : PG_RETURN_INTERVAL_P(result);
4573 : }
4574 :
4575 :
4576 : /*----------------------------------------------------------
4577 : * Conversion operators.
4578 : *---------------------------------------------------------*/
4579 :
4580 :
4581 : /* timestamp_bin()
4582 : * Bin timestamp into specified interval.
4583 : */
4584 : Datum
4585 276 : timestamp_bin(PG_FUNCTION_ARGS)
4586 : {
4587 276 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4588 276 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4589 276 : Timestamp origin = PG_GETARG_TIMESTAMP(2);
4590 : Timestamp result,
4591 : stride_usecs,
4592 : tm_diff,
4593 : tm_modulo,
4594 : tm_delta;
4595 :
4596 276 : if (TIMESTAMP_NOT_FINITE(timestamp))
4597 0 : PG_RETURN_TIMESTAMP(timestamp);
4598 :
4599 276 : if (TIMESTAMP_NOT_FINITE(origin))
4600 0 : ereport(ERROR,
4601 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4602 : errmsg("origin out of range")));
4603 :
4604 276 : if (INTERVAL_NOT_FINITE(stride))
4605 12 : ereport(ERROR,
4606 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4607 : errmsg("timestamps cannot be binned into infinite intervals")));
4608 :
4609 264 : if (stride->month != 0)
4610 12 : ereport(ERROR,
4611 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4612 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4613 :
4614 252 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4615 246 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4616 6 : ereport(ERROR,
4617 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4618 : errmsg("interval out of range")));
4619 :
4620 246 : if (stride_usecs <= 0)
4621 12 : ereport(ERROR,
4622 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4623 : errmsg("stride must be greater than zero")));
4624 :
4625 234 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4626 6 : ereport(ERROR,
4627 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4628 : errmsg("interval out of range")));
4629 :
4630 : /* These calculations cannot overflow */
4631 228 : tm_modulo = tm_diff % stride_usecs;
4632 228 : tm_delta = tm_diff - tm_modulo;
4633 228 : result = origin + tm_delta;
4634 :
4635 : /*
4636 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4637 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4638 : * since the result might now be out of the range origin .. timestamp.
4639 : */
4640 228 : if (tm_modulo < 0)
4641 : {
4642 78 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4643 78 : !IS_VALID_TIMESTAMP(result))
4644 6 : ereport(ERROR,
4645 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4646 : errmsg("timestamp out of range")));
4647 : }
4648 :
4649 222 : PG_RETURN_TIMESTAMP(result);
4650 : }
4651 :
4652 : /* timestamp_trunc()
4653 : * Truncate timestamp to specified units.
4654 : */
4655 : Datum
4656 1410 : timestamp_trunc(PG_FUNCTION_ARGS)
4657 : {
4658 1410 : text *units = PG_GETARG_TEXT_PP(0);
4659 1410 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4660 : Timestamp result;
4661 : int type,
4662 : val;
4663 : char *lowunits;
4664 : fsec_t fsec;
4665 : struct pg_tm tt,
4666 1410 : *tm = &tt;
4667 :
4668 1410 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4669 1410 : VARSIZE_ANY_EXHDR(units),
4670 : false);
4671 :
4672 1410 : type = DecodeUnits(0, lowunits, &val);
4673 :
4674 1410 : if (type == UNITS)
4675 : {
4676 1404 : if (TIMESTAMP_NOT_FINITE(timestamp))
4677 : {
4678 : /*
4679 : * Errors thrown here for invalid units should exactly match those
4680 : * below, else there will be unexpected discrepancies between
4681 : * finite- and infinite-input cases.
4682 : */
4683 12 : switch (val)
4684 : {
4685 6 : case DTK_WEEK:
4686 : case DTK_MILLENNIUM:
4687 : case DTK_CENTURY:
4688 : case DTK_DECADE:
4689 : case DTK_YEAR:
4690 : case DTK_QUARTER:
4691 : case DTK_MONTH:
4692 : case DTK_DAY:
4693 : case DTK_HOUR:
4694 : case DTK_MINUTE:
4695 : case DTK_SECOND:
4696 : case DTK_MILLISEC:
4697 : case DTK_MICROSEC:
4698 6 : PG_RETURN_TIMESTAMP(timestamp);
4699 : break;
4700 6 : default:
4701 6 : ereport(ERROR,
4702 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4703 : errmsg("unit \"%s\" not supported for type %s",
4704 : lowunits, format_type_be(TIMESTAMPOID))));
4705 : result = 0;
4706 : }
4707 : }
4708 :
4709 1392 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4710 0 : ereport(ERROR,
4711 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4712 : errmsg("timestamp out of range")));
4713 :
4714 1392 : switch (val)
4715 : {
4716 30 : case DTK_WEEK:
4717 : {
4718 : int woy;
4719 :
4720 30 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4721 :
4722 : /*
4723 : * If it is week 52/53 and the month is January, then the
4724 : * week must belong to the previous year. Also, some
4725 : * December dates belong to the next year.
4726 : */
4727 30 : if (woy >= 52 && tm->tm_mon == 1)
4728 0 : --tm->tm_year;
4729 30 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4730 0 : ++tm->tm_year;
4731 30 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4732 30 : tm->tm_hour = 0;
4733 30 : tm->tm_min = 0;
4734 30 : tm->tm_sec = 0;
4735 30 : fsec = 0;
4736 30 : break;
4737 : }
4738 6 : case DTK_MILLENNIUM:
4739 : /* see comments in timestamptz_trunc */
4740 6 : if (tm->tm_year > 0)
4741 6 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4742 : else
4743 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4744 : /* FALL THRU */
4745 : case DTK_CENTURY:
4746 : /* see comments in timestamptz_trunc */
4747 12 : if (tm->tm_year > 0)
4748 12 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4749 : else
4750 0 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4751 : /* FALL THRU */
4752 : case DTK_DECADE:
4753 : /* see comments in timestamptz_trunc */
4754 12 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4755 : {
4756 0 : if (tm->tm_year > 0)
4757 0 : tm->tm_year = (tm->tm_year / 10) * 10;
4758 : else
4759 0 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4760 : }
4761 : /* FALL THRU */
4762 : case DTK_YEAR:
4763 12 : tm->tm_mon = 1;
4764 : /* FALL THRU */
4765 12 : case DTK_QUARTER:
4766 12 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4767 : /* FALL THRU */
4768 12 : case DTK_MONTH:
4769 12 : tm->tm_mday = 1;
4770 : /* FALL THRU */
4771 1236 : case DTK_DAY:
4772 1236 : tm->tm_hour = 0;
4773 : /* FALL THRU */
4774 1260 : case DTK_HOUR:
4775 1260 : tm->tm_min = 0;
4776 : /* FALL THRU */
4777 1284 : case DTK_MINUTE:
4778 1284 : tm->tm_sec = 0;
4779 : /* FALL THRU */
4780 1308 : case DTK_SECOND:
4781 1308 : fsec = 0;
4782 1308 : break;
4783 :
4784 24 : case DTK_MILLISEC:
4785 24 : fsec = (fsec / 1000) * 1000;
4786 24 : break;
4787 :
4788 24 : case DTK_MICROSEC:
4789 24 : break;
4790 :
4791 6 : default:
4792 6 : ereport(ERROR,
4793 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4794 : errmsg("unit \"%s\" not supported for type %s",
4795 : lowunits, format_type_be(TIMESTAMPOID))));
4796 : result = 0;
4797 : }
4798 :
4799 1386 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
4800 0 : ereport(ERROR,
4801 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4802 : errmsg("timestamp out of range")));
4803 : }
4804 : else
4805 : {
4806 6 : ereport(ERROR,
4807 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4808 : errmsg("unit \"%s\" not recognized for type %s",
4809 : lowunits, format_type_be(TIMESTAMPOID))));
4810 : result = 0;
4811 : }
4812 :
4813 1386 : PG_RETURN_TIMESTAMP(result);
4814 : }
4815 :
4816 : /* timestamptz_bin()
4817 : * Bin timestamptz into specified interval using specified origin.
4818 : */
4819 : Datum
4820 132 : timestamptz_bin(PG_FUNCTION_ARGS)
4821 : {
4822 132 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4823 132 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
4824 132 : TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
4825 : TimestampTz result,
4826 : stride_usecs,
4827 : tm_diff,
4828 : tm_modulo,
4829 : tm_delta;
4830 :
4831 132 : if (TIMESTAMP_NOT_FINITE(timestamp))
4832 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
4833 :
4834 132 : if (TIMESTAMP_NOT_FINITE(origin))
4835 0 : ereport(ERROR,
4836 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4837 : errmsg("origin out of range")));
4838 :
4839 132 : if (INTERVAL_NOT_FINITE(stride))
4840 0 : ereport(ERROR,
4841 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4842 : errmsg("timestamps cannot be binned into infinite intervals")));
4843 :
4844 132 : if (stride->month != 0)
4845 12 : ereport(ERROR,
4846 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4847 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4848 :
4849 120 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4850 114 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4851 6 : ereport(ERROR,
4852 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4853 : errmsg("interval out of range")));
4854 :
4855 114 : if (stride_usecs <= 0)
4856 12 : ereport(ERROR,
4857 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4858 : errmsg("stride must be greater than zero")));
4859 :
4860 102 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4861 6 : ereport(ERROR,
4862 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4863 : errmsg("interval out of range")));
4864 :
4865 : /* These calculations cannot overflow */
4866 96 : tm_modulo = tm_diff % stride_usecs;
4867 96 : tm_delta = tm_diff - tm_modulo;
4868 96 : result = origin + tm_delta;
4869 :
4870 : /*
4871 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4872 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4873 : * since the result might now be out of the range origin .. timestamp.
4874 : */
4875 96 : if (tm_modulo < 0)
4876 : {
4877 6 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4878 6 : !IS_VALID_TIMESTAMP(result))
4879 6 : ereport(ERROR,
4880 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4881 : errmsg("timestamp out of range")));
4882 : }
4883 :
4884 90 : PG_RETURN_TIMESTAMPTZ(result);
4885 : }
4886 :
4887 : /*
4888 : * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
4889 : *
4890 : * tzp identifies the zone to truncate with respect to. We assume
4891 : * infinite timestamps have already been rejected.
4892 : */
4893 : static TimestampTz
4894 1350 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
4895 : {
4896 : TimestampTz result;
4897 : int tz;
4898 : int type,
4899 : val;
4900 1350 : bool redotz = false;
4901 : char *lowunits;
4902 : fsec_t fsec;
4903 : struct pg_tm tt,
4904 1350 : *tm = &tt;
4905 :
4906 1350 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4907 1350 : VARSIZE_ANY_EXHDR(units),
4908 : false);
4909 :
4910 1350 : type = DecodeUnits(0, lowunits, &val);
4911 :
4912 1350 : if (type == UNITS)
4913 : {
4914 1338 : if (TIMESTAMP_NOT_FINITE(timestamp))
4915 : {
4916 : /*
4917 : * Errors thrown here for invalid units should exactly match those
4918 : * below, else there will be unexpected discrepancies between
4919 : * finite- and infinite-input cases.
4920 : */
4921 24 : switch (val)
4922 : {
4923 12 : case DTK_WEEK:
4924 : case DTK_MILLENNIUM:
4925 : case DTK_CENTURY:
4926 : case DTK_DECADE:
4927 : case DTK_YEAR:
4928 : case DTK_QUARTER:
4929 : case DTK_MONTH:
4930 : case DTK_DAY:
4931 : case DTK_HOUR:
4932 : case DTK_MINUTE:
4933 : case DTK_SECOND:
4934 : case DTK_MILLISEC:
4935 : case DTK_MICROSEC:
4936 12 : return timestamp;
4937 : break;
4938 :
4939 12 : default:
4940 12 : ereport(ERROR,
4941 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4942 : errmsg("unit \"%s\" not supported for type %s",
4943 : lowunits, format_type_be(TIMESTAMPTZOID))));
4944 : result = 0;
4945 : }
4946 : }
4947 :
4948 1314 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
4949 0 : ereport(ERROR,
4950 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4951 : errmsg("timestamp out of range")));
4952 :
4953 1314 : switch (val)
4954 : {
4955 6 : case DTK_WEEK:
4956 : {
4957 : int woy;
4958 :
4959 6 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4960 :
4961 : /*
4962 : * If it is week 52/53 and the month is January, then the
4963 : * week must belong to the previous year. Also, some
4964 : * December dates belong to the next year.
4965 : */
4966 6 : if (woy >= 52 && tm->tm_mon == 1)
4967 0 : --tm->tm_year;
4968 6 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4969 0 : ++tm->tm_year;
4970 6 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4971 6 : tm->tm_hour = 0;
4972 6 : tm->tm_min = 0;
4973 6 : tm->tm_sec = 0;
4974 6 : fsec = 0;
4975 6 : redotz = true;
4976 6 : break;
4977 : }
4978 : /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
4979 6 : case DTK_MILLENNIUM:
4980 :
4981 : /*
4982 : * truncating to the millennium? what is this supposed to
4983 : * mean? let us put the first year of the millennium... i.e.
4984 : * -1000, 1, 1001, 2001...
4985 : */
4986 6 : if (tm->tm_year > 0)
4987 6 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4988 : else
4989 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4990 : /* FALL THRU */
4991 : case DTK_CENTURY:
4992 : /* truncating to the century? as above: -100, 1, 101... */
4993 30 : if (tm->tm_year > 0)
4994 24 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4995 : else
4996 6 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4997 : /* FALL THRU */
4998 : case DTK_DECADE:
4999 :
5000 : /*
5001 : * truncating to the decade? first year of the decade. must
5002 : * not be applied if year was truncated before!
5003 : */
5004 48 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
5005 : {
5006 18 : if (tm->tm_year > 0)
5007 12 : tm->tm_year = (tm->tm_year / 10) * 10;
5008 : else
5009 6 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
5010 : }
5011 : /* FALL THRU */
5012 : case DTK_YEAR:
5013 48 : tm->tm_mon = 1;
5014 : /* FALL THRU */
5015 48 : case DTK_QUARTER:
5016 48 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
5017 : /* FALL THRU */
5018 48 : case DTK_MONTH:
5019 48 : tm->tm_mday = 1;
5020 : /* FALL THRU */
5021 1272 : case DTK_DAY:
5022 1272 : tm->tm_hour = 0;
5023 1272 : redotz = true; /* for all cases >= DAY */
5024 : /* FALL THRU */
5025 1278 : case DTK_HOUR:
5026 1278 : tm->tm_min = 0;
5027 : /* FALL THRU */
5028 1284 : case DTK_MINUTE:
5029 1284 : tm->tm_sec = 0;
5030 : /* FALL THRU */
5031 1290 : case DTK_SECOND:
5032 1290 : fsec = 0;
5033 1290 : break;
5034 6 : case DTK_MILLISEC:
5035 6 : fsec = (fsec / 1000) * 1000;
5036 6 : break;
5037 6 : case DTK_MICROSEC:
5038 6 : break;
5039 :
5040 6 : default:
5041 6 : ereport(ERROR,
5042 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5043 : errmsg("unit \"%s\" not supported for type %s",
5044 : lowunits, format_type_be(TIMESTAMPTZOID))));
5045 : result = 0;
5046 : }
5047 :
5048 1308 : if (redotz)
5049 1278 : tz = DetermineTimeZoneOffset(tm, tzp);
5050 :
5051 1308 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
5052 0 : ereport(ERROR,
5053 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5054 : errmsg("timestamp out of range")));
5055 : }
5056 : else
5057 : {
5058 12 : ereport(ERROR,
5059 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5060 : errmsg("unit \"%s\" not recognized for type %s",
5061 : lowunits, format_type_be(TIMESTAMPTZOID))));
5062 : result = 0;
5063 : }
5064 :
5065 1308 : return result;
5066 : }
5067 :
5068 : /* timestamptz_trunc()
5069 : * Truncate timestamptz to specified units in session timezone.
5070 : */
5071 : Datum
5072 1278 : timestamptz_trunc(PG_FUNCTION_ARGS)
5073 : {
5074 1278 : text *units = PG_GETARG_TEXT_PP(0);
5075 1278 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5076 : TimestampTz result;
5077 :
5078 1278 : result = timestamptz_trunc_internal(units, timestamp, session_timezone);
5079 :
5080 1260 : PG_RETURN_TIMESTAMPTZ(result);
5081 : }
5082 :
5083 : /* timestamptz_trunc_zone()
5084 : * Truncate timestamptz to specified units in specified timezone.
5085 : */
5086 : Datum
5087 72 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
5088 : {
5089 72 : text *units = PG_GETARG_TEXT_PP(0);
5090 72 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5091 72 : text *zone = PG_GETARG_TEXT_PP(2);
5092 : TimestampTz result;
5093 : pg_tz *tzp;
5094 :
5095 : /*
5096 : * Look up the requested timezone.
5097 : */
5098 72 : tzp = lookup_timezone(zone);
5099 :
5100 72 : result = timestamptz_trunc_internal(units, timestamp, tzp);
5101 :
5102 60 : PG_RETURN_TIMESTAMPTZ(result);
5103 : }
5104 :
5105 : /* interval_trunc()
5106 : * Extract specified field from interval.
5107 : */
5108 : Datum
5109 24 : interval_trunc(PG_FUNCTION_ARGS)
5110 : {
5111 24 : text *units = PG_GETARG_TEXT_PP(0);
5112 24 : Interval *interval = PG_GETARG_INTERVAL_P(1);
5113 : Interval *result;
5114 : int type,
5115 : val;
5116 : char *lowunits;
5117 : struct pg_itm tt,
5118 24 : *tm = &tt;
5119 :
5120 24 : result = (Interval *) palloc(sizeof(Interval));
5121 :
5122 24 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5123 24 : VARSIZE_ANY_EXHDR(units),
5124 : false);
5125 :
5126 24 : type = DecodeUnits(0, lowunits, &val);
5127 :
5128 24 : if (type == UNITS)
5129 : {
5130 18 : if (INTERVAL_NOT_FINITE(interval))
5131 : {
5132 : /*
5133 : * Errors thrown here for invalid units should exactly match those
5134 : * below, else there will be unexpected discrepancies between
5135 : * finite- and infinite-input cases.
5136 : */
5137 18 : switch (val)
5138 : {
5139 12 : case DTK_MILLENNIUM:
5140 : case DTK_CENTURY:
5141 : case DTK_DECADE:
5142 : case DTK_YEAR:
5143 : case DTK_QUARTER:
5144 : case DTK_MONTH:
5145 : case DTK_DAY:
5146 : case DTK_HOUR:
5147 : case DTK_MINUTE:
5148 : case DTK_SECOND:
5149 : case DTK_MILLISEC:
5150 : case DTK_MICROSEC:
5151 12 : memcpy(result, interval, sizeof(Interval));
5152 12 : PG_RETURN_INTERVAL_P(result);
5153 : break;
5154 :
5155 6 : default:
5156 6 : ereport(ERROR,
5157 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5158 : errmsg("unit \"%s\" not supported for type %s",
5159 : lowunits, format_type_be(INTERVALOID)),
5160 : (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
5161 : result = 0;
5162 : }
5163 : }
5164 :
5165 0 : interval2itm(*interval, tm);
5166 0 : switch (val)
5167 : {
5168 0 : case DTK_MILLENNIUM:
5169 : /* caution: C division may have negative remainder */
5170 0 : tm->tm_year = (tm->tm_year / 1000) * 1000;
5171 : /* FALL THRU */
5172 0 : case DTK_CENTURY:
5173 : /* caution: C division may have negative remainder */
5174 0 : tm->tm_year = (tm->tm_year / 100) * 100;
5175 : /* FALL THRU */
5176 0 : case DTK_DECADE:
5177 : /* caution: C division may have negative remainder */
5178 0 : tm->tm_year = (tm->tm_year / 10) * 10;
5179 : /* FALL THRU */
5180 0 : case DTK_YEAR:
5181 0 : tm->tm_mon = 0;
5182 : /* FALL THRU */
5183 0 : case DTK_QUARTER:
5184 0 : tm->tm_mon = 3 * (tm->tm_mon / 3);
5185 : /* FALL THRU */
5186 0 : case DTK_MONTH:
5187 0 : tm->tm_mday = 0;
5188 : /* FALL THRU */
5189 0 : case DTK_DAY:
5190 0 : tm->tm_hour = 0;
5191 : /* FALL THRU */
5192 0 : case DTK_HOUR:
5193 0 : tm->tm_min = 0;
5194 : /* FALL THRU */
5195 0 : case DTK_MINUTE:
5196 0 : tm->tm_sec = 0;
5197 : /* FALL THRU */
5198 0 : case DTK_SECOND:
5199 0 : tm->tm_usec = 0;
5200 0 : break;
5201 0 : case DTK_MILLISEC:
5202 0 : tm->tm_usec = (tm->tm_usec / 1000) * 1000;
5203 0 : break;
5204 0 : case DTK_MICROSEC:
5205 0 : break;
5206 :
5207 0 : default:
5208 0 : ereport(ERROR,
5209 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5210 : errmsg("unit \"%s\" not supported for type %s",
5211 : lowunits, format_type_be(INTERVALOID)),
5212 : (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
5213 : }
5214 :
5215 0 : if (itm2interval(tm, result) != 0)
5216 0 : ereport(ERROR,
5217 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5218 : errmsg("interval out of range")));
5219 : }
5220 : else
5221 : {
5222 6 : ereport(ERROR,
5223 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5224 : errmsg("unit \"%s\" not recognized for type %s",
5225 : lowunits, format_type_be(INTERVALOID))));
5226 : }
5227 :
5228 0 : PG_RETURN_INTERVAL_P(result);
5229 : }
5230 :
5231 : /* isoweek2j()
5232 : *
5233 : * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
5234 : * Julian days are used to convert between ISO week dates and Gregorian dates.
5235 : *
5236 : * XXX: This function has integer overflow hazards, but restructuring it to
5237 : * work with the soft-error handling that its callers do is likely more
5238 : * trouble than it's worth.
5239 : */
5240 : int
5241 1590 : isoweek2j(int year, int week)
5242 : {
5243 : int day0,
5244 : day4;
5245 :
5246 : /* fourth day of current year */
5247 1590 : day4 = date2j(year, 1, 4);
5248 :
5249 : /* day0 == offset to first day of week (Monday) */
5250 1590 : day0 = j2day(day4 - 1);
5251 :
5252 1590 : return ((week - 1) * 7) + (day4 - day0);
5253 : }
5254 :
5255 : /* isoweek2date()
5256 : * Convert ISO week of year number to date.
5257 : * The year field must be specified with the ISO year!
5258 : * karel 2000/08/07
5259 : */
5260 : void
5261 36 : isoweek2date(int woy, int *year, int *mon, int *mday)
5262 : {
5263 36 : j2date(isoweek2j(*year, woy), year, mon, mday);
5264 36 : }
5265 :
5266 : /* isoweekdate2date()
5267 : *
5268 : * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
5269 : * Gregorian day of week sent so weekday strings can be supplied.
5270 : * Populates year, mon, and mday with the correct Gregorian values.
5271 : * year must be passed in as the ISO year.
5272 : */
5273 : void
5274 24 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
5275 : {
5276 : int jday;
5277 :
5278 24 : jday = isoweek2j(*year, isoweek);
5279 : /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
5280 24 : if (wday > 1)
5281 0 : jday += wday - 2;
5282 : else
5283 24 : jday += 6;
5284 24 : j2date(jday, year, mon, mday);
5285 24 : }
5286 :
5287 : /* date2isoweek()
5288 : *
5289 : * Returns ISO week number of year.
5290 : */
5291 : int
5292 2424 : date2isoweek(int year, int mon, int mday)
5293 : {
5294 : int day0,
5295 : day4,
5296 : dayn,
5297 : week;
5298 :
5299 : /* current day */
5300 2424 : dayn = date2j(year, mon, mday);
5301 :
5302 : /* fourth day of current year */
5303 2424 : day4 = date2j(year, 1, 4);
5304 :
5305 : /* day0 == offset to first day of week (Monday) */
5306 2424 : day0 = j2day(day4 - 1);
5307 :
5308 : /*
5309 : * We need the first week containing a Thursday, otherwise this day falls
5310 : * into the previous year for purposes of counting weeks
5311 : */
5312 2424 : if (dayn < day4 - day0)
5313 : {
5314 36 : day4 = date2j(year - 1, 1, 4);
5315 :
5316 : /* day0 == offset to first day of week (Monday) */
5317 36 : day0 = j2day(day4 - 1);
5318 : }
5319 :
5320 2424 : week = (dayn - (day4 - day0)) / 7 + 1;
5321 :
5322 : /*
5323 : * Sometimes the last few days in a year will fall into the first week of
5324 : * the next year, so check for this.
5325 : */
5326 2424 : if (week >= 52)
5327 : {
5328 270 : day4 = date2j(year + 1, 1, 4);
5329 :
5330 : /* day0 == offset to first day of week (Monday) */
5331 270 : day0 = j2day(day4 - 1);
5332 :
5333 270 : if (dayn >= day4 - day0)
5334 162 : week = (dayn - (day4 - day0)) / 7 + 1;
5335 : }
5336 :
5337 2424 : return week;
5338 : }
5339 :
5340 :
5341 : /* date2isoyear()
5342 : *
5343 : * Returns ISO 8601 year number.
5344 : * Note: zero or negative results follow the year-zero-exists convention.
5345 : */
5346 : int
5347 14586 : date2isoyear(int year, int mon, int mday)
5348 : {
5349 : int day0,
5350 : day4,
5351 : dayn,
5352 : week;
5353 :
5354 : /* current day */
5355 14586 : dayn = date2j(year, mon, mday);
5356 :
5357 : /* fourth day of current year */
5358 14586 : day4 = date2j(year, 1, 4);
5359 :
5360 : /* day0 == offset to first day of week (Monday) */
5361 14586 : day0 = j2day(day4 - 1);
5362 :
5363 : /*
5364 : * We need the first week containing a Thursday, otherwise this day falls
5365 : * into the previous year for purposes of counting weeks
5366 : */
5367 14586 : if (dayn < day4 - day0)
5368 : {
5369 228 : day4 = date2j(year - 1, 1, 4);
5370 :
5371 : /* day0 == offset to first day of week (Monday) */
5372 228 : day0 = j2day(day4 - 1);
5373 :
5374 228 : year--;
5375 : }
5376 :
5377 14586 : week = (dayn - (day4 - day0)) / 7 + 1;
5378 :
5379 : /*
5380 : * Sometimes the last few days in a year will fall into the first week of
5381 : * the next year, so check for this.
5382 : */
5383 14586 : if (week >= 52)
5384 : {
5385 1710 : day4 = date2j(year + 1, 1, 4);
5386 :
5387 : /* day0 == offset to first day of week (Monday) */
5388 1710 : day0 = j2day(day4 - 1);
5389 :
5390 1710 : if (dayn >= day4 - day0)
5391 1026 : year++;
5392 : }
5393 :
5394 14586 : return year;
5395 : }
5396 :
5397 :
5398 : /* date2isoyearday()
5399 : *
5400 : * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
5401 : * Possible return values are 1 through 371 (364 in non-leap years).
5402 : */
5403 : int
5404 1524 : date2isoyearday(int year, int mon, int mday)
5405 : {
5406 1524 : return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
5407 : }
5408 :
5409 : /*
5410 : * NonFiniteTimestampTzPart
5411 : *
5412 : * Used by timestamp_part and timestamptz_part when extracting from infinite
5413 : * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
5414 : * otherwise returns zero (which should be taken as meaning to return NULL).
5415 : *
5416 : * Errors thrown here for invalid units should exactly match those that
5417 : * would be thrown in the calling functions, else there will be unexpected
5418 : * discrepancies between finite- and infinite-input cases.
5419 : */
5420 : static float8
5421 612 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
5422 : bool isNegative, bool isTz)
5423 : {
5424 612 : if ((type != UNITS) && (type != RESERV))
5425 0 : ereport(ERROR,
5426 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5427 : errmsg("unit \"%s\" not recognized for type %s",
5428 : lowunits,
5429 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5430 :
5431 612 : switch (unit)
5432 : {
5433 : /* Oscillating units */
5434 396 : case DTK_MICROSEC:
5435 : case DTK_MILLISEC:
5436 : case DTK_SECOND:
5437 : case DTK_MINUTE:
5438 : case DTK_HOUR:
5439 : case DTK_DAY:
5440 : case DTK_MONTH:
5441 : case DTK_QUARTER:
5442 : case DTK_WEEK:
5443 : case DTK_DOW:
5444 : case DTK_ISODOW:
5445 : case DTK_DOY:
5446 : case DTK_TZ:
5447 : case DTK_TZ_MINUTE:
5448 : case DTK_TZ_HOUR:
5449 396 : return 0.0;
5450 :
5451 : /* Monotonically-increasing units */
5452 216 : case DTK_YEAR:
5453 : case DTK_DECADE:
5454 : case DTK_CENTURY:
5455 : case DTK_MILLENNIUM:
5456 : case DTK_JULIAN:
5457 : case DTK_ISOYEAR:
5458 : case DTK_EPOCH:
5459 216 : if (isNegative)
5460 108 : return -get_float8_infinity();
5461 : else
5462 108 : return get_float8_infinity();
5463 :
5464 0 : default:
5465 0 : ereport(ERROR,
5466 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5467 : errmsg("unit \"%s\" not supported for type %s",
5468 : lowunits,
5469 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5470 : return 0.0; /* keep compiler quiet */
5471 : }
5472 : }
5473 :
5474 : /* timestamp_part() and extract_timestamp()
5475 : * Extract specified field from timestamp.
5476 : */
5477 : static Datum
5478 10722 : timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5479 : {
5480 10722 : text *units = PG_GETARG_TEXT_PP(0);
5481 10722 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
5482 : int64 intresult;
5483 : Timestamp epoch;
5484 : int type,
5485 : val;
5486 : char *lowunits;
5487 : fsec_t fsec;
5488 : struct pg_tm tt,
5489 10722 : *tm = &tt;
5490 :
5491 10722 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5492 10722 : VARSIZE_ANY_EXHDR(units),
5493 : false);
5494 :
5495 10722 : type = DecodeUnits(0, lowunits, &val);
5496 10722 : if (type == UNKNOWN_FIELD)
5497 3714 : type = DecodeSpecial(0, lowunits, &val);
5498 :
5499 10722 : if (TIMESTAMP_NOT_FINITE(timestamp))
5500 : {
5501 288 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5502 : TIMESTAMP_IS_NOBEGIN(timestamp),
5503 : false);
5504 :
5505 288 : if (r != 0.0)
5506 : {
5507 108 : if (retnumeric)
5508 : {
5509 24 : if (r < 0)
5510 12 : return DirectFunctionCall3(numeric_in,
5511 : CStringGetDatum("-Infinity"),
5512 : ObjectIdGetDatum(InvalidOid),
5513 : Int32GetDatum(-1));
5514 12 : else if (r > 0)
5515 12 : return DirectFunctionCall3(numeric_in,
5516 : CStringGetDatum("Infinity"),
5517 : ObjectIdGetDatum(InvalidOid),
5518 : Int32GetDatum(-1));
5519 : }
5520 : else
5521 84 : PG_RETURN_FLOAT8(r);
5522 : }
5523 : else
5524 180 : PG_RETURN_NULL();
5525 : }
5526 :
5527 10434 : if (type == UNITS)
5528 : {
5529 9564 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
5530 0 : ereport(ERROR,
5531 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5532 : errmsg("timestamp out of range")));
5533 :
5534 9564 : switch (val)
5535 : {
5536 756 : case DTK_MICROSEC:
5537 756 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5538 756 : break;
5539 :
5540 756 : case DTK_MILLISEC:
5541 756 : if (retnumeric)
5542 : /*---
5543 : * tm->tm_sec * 1000 + fsec / 1000
5544 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5545 : */
5546 378 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5547 : else
5548 378 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5549 : break;
5550 :
5551 756 : case DTK_SECOND:
5552 756 : if (retnumeric)
5553 : /*---
5554 : * tm->tm_sec + fsec / 1'000'000
5555 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5556 : */
5557 378 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5558 : else
5559 378 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5560 : break;
5561 :
5562 378 : case DTK_MINUTE:
5563 378 : intresult = tm->tm_min;
5564 378 : break;
5565 :
5566 378 : case DTK_HOUR:
5567 378 : intresult = tm->tm_hour;
5568 378 : break;
5569 :
5570 474 : case DTK_DAY:
5571 474 : intresult = tm->tm_mday;
5572 474 : break;
5573 :
5574 474 : case DTK_MONTH:
5575 474 : intresult = tm->tm_mon;
5576 474 : break;
5577 :
5578 474 : case DTK_QUARTER:
5579 474 : intresult = (tm->tm_mon - 1) / 3 + 1;
5580 474 : break;
5581 :
5582 474 : case DTK_WEEK:
5583 474 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5584 474 : break;
5585 :
5586 474 : case DTK_YEAR:
5587 474 : if (tm->tm_year > 0)
5588 462 : intresult = tm->tm_year;
5589 : else
5590 : /* there is no year 0, just 1 BC and 1 AD */
5591 12 : intresult = tm->tm_year - 1;
5592 474 : break;
5593 :
5594 474 : case DTK_DECADE:
5595 :
5596 : /*
5597 : * what is a decade wrt dates? let us assume that decade 199
5598 : * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
5599 : * is 11 BC thru 2 BC...
5600 : */
5601 474 : if (tm->tm_year >= 0)
5602 462 : intresult = tm->tm_year / 10;
5603 : else
5604 12 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5605 474 : break;
5606 :
5607 474 : case DTK_CENTURY:
5608 :
5609 : /* ----
5610 : * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
5611 : * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
5612 : * there is no number 0 century.
5613 : * ----
5614 : */
5615 474 : if (tm->tm_year > 0)
5616 462 : intresult = (tm->tm_year + 99) / 100;
5617 : else
5618 : /* caution: C division may have negative remainder */
5619 12 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5620 474 : break;
5621 :
5622 474 : case DTK_MILLENNIUM:
5623 : /* see comments above. */
5624 474 : if (tm->tm_year > 0)
5625 462 : intresult = (tm->tm_year + 999) / 1000;
5626 : else
5627 12 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5628 474 : break;
5629 :
5630 852 : case DTK_JULIAN:
5631 852 : if (retnumeric)
5632 378 : PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5633 : 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),
5634 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5635 : NULL),
5636 : NULL));
5637 : else
5638 474 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5639 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5640 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5641 : break;
5642 :
5643 474 : case DTK_ISOYEAR:
5644 474 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5645 : /* Adjust BC years */
5646 474 : if (intresult <= 0)
5647 12 : intresult -= 1;
5648 474 : break;
5649 :
5650 948 : case DTK_DOW:
5651 : case DTK_ISODOW:
5652 948 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5653 948 : if (val == DTK_ISODOW && intresult == 0)
5654 30 : intresult = 7;
5655 948 : break;
5656 :
5657 474 : case DTK_DOY:
5658 474 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5659 474 : - date2j(tm->tm_year, 1, 1) + 1);
5660 474 : break;
5661 :
5662 0 : case DTK_TZ:
5663 : case DTK_TZ_MINUTE:
5664 : case DTK_TZ_HOUR:
5665 : default:
5666 0 : ereport(ERROR,
5667 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5668 : errmsg("unit \"%s\" not supported for type %s",
5669 : lowunits, format_type_be(TIMESTAMPOID))));
5670 : intresult = 0;
5671 : }
5672 : }
5673 870 : else if (type == RESERV)
5674 : {
5675 870 : switch (val)
5676 : {
5677 870 : case DTK_EPOCH:
5678 870 : epoch = SetEpochTimestamp();
5679 : /* (timestamp - epoch) / 1000000 */
5680 870 : if (retnumeric)
5681 : {
5682 : Numeric result;
5683 :
5684 390 : if (timestamp < (PG_INT64_MAX + epoch))
5685 384 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5686 : else
5687 : {
5688 6 : result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
5689 : int64_to_numeric(epoch),
5690 : NULL),
5691 : int64_to_numeric(1000000),
5692 : NULL);
5693 6 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5694 : NumericGetDatum(result),
5695 : Int32GetDatum(6)));
5696 : }
5697 390 : PG_RETURN_NUMERIC(result);
5698 : }
5699 : else
5700 : {
5701 : float8 result;
5702 :
5703 : /* try to avoid precision loss in subtraction */
5704 480 : if (timestamp < (PG_INT64_MAX + epoch))
5705 474 : result = (timestamp - epoch) / 1000000.0;
5706 : else
5707 6 : result = ((float8) timestamp - epoch) / 1000000.0;
5708 480 : PG_RETURN_FLOAT8(result);
5709 : }
5710 : break;
5711 :
5712 0 : default:
5713 0 : ereport(ERROR,
5714 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5715 : errmsg("unit \"%s\" not supported for type %s",
5716 : lowunits, format_type_be(TIMESTAMPOID))));
5717 : intresult = 0;
5718 : }
5719 : }
5720 : else
5721 : {
5722 0 : ereport(ERROR,
5723 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5724 : errmsg("unit \"%s\" not recognized for type %s",
5725 : lowunits, format_type_be(TIMESTAMPOID))));
5726 : intresult = 0;
5727 : }
5728 :
5729 7200 : if (retnumeric)
5730 378 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
5731 : else
5732 6822 : PG_RETURN_FLOAT8(intresult);
5733 : }
5734 :
5735 : Datum
5736 8760 : timestamp_part(PG_FUNCTION_ARGS)
5737 : {
5738 8760 : return timestamp_part_common(fcinfo, false);
5739 : }
5740 :
5741 : Datum
5742 1962 : extract_timestamp(PG_FUNCTION_ARGS)
5743 : {
5744 1962 : return timestamp_part_common(fcinfo, true);
5745 : }
5746 :
5747 : /* timestamptz_part() and extract_timestamptz()
5748 : * Extract specified field from timestamp with time zone.
5749 : */
5750 : static Datum
5751 37468 : timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5752 : {
5753 37468 : text *units = PG_GETARG_TEXT_PP(0);
5754 37468 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5755 : int64 intresult;
5756 : Timestamp epoch;
5757 : int tz;
5758 : int type,
5759 : val;
5760 : char *lowunits;
5761 : fsec_t fsec;
5762 : struct pg_tm tt,
5763 37468 : *tm = &tt;
5764 :
5765 37468 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5766 37468 : VARSIZE_ANY_EXHDR(units),
5767 : false);
5768 :
5769 37468 : type = DecodeUnits(0, lowunits, &val);
5770 37468 : if (type == UNKNOWN_FIELD)
5771 29920 : type = DecodeSpecial(0, lowunits, &val);
5772 :
5773 37468 : if (TIMESTAMP_NOT_FINITE(timestamp))
5774 : {
5775 324 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5776 : TIMESTAMP_IS_NOBEGIN(timestamp),
5777 : true);
5778 :
5779 324 : if (r != 0.0)
5780 : {
5781 108 : if (retnumeric)
5782 : {
5783 24 : if (r < 0)
5784 12 : return DirectFunctionCall3(numeric_in,
5785 : CStringGetDatum("-Infinity"),
5786 : ObjectIdGetDatum(InvalidOid),
5787 : Int32GetDatum(-1));
5788 12 : else if (r > 0)
5789 12 : return DirectFunctionCall3(numeric_in,
5790 : CStringGetDatum("Infinity"),
5791 : ObjectIdGetDatum(InvalidOid),
5792 : Int32GetDatum(-1));
5793 : }
5794 : else
5795 84 : PG_RETURN_FLOAT8(r);
5796 : }
5797 : else
5798 216 : PG_RETURN_NULL();
5799 : }
5800 :
5801 37144 : if (type == UNITS)
5802 : {
5803 9684 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5804 0 : ereport(ERROR,
5805 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5806 : errmsg("timestamp out of range")));
5807 :
5808 9684 : switch (val)
5809 : {
5810 384 : case DTK_TZ:
5811 384 : intresult = -tz;
5812 384 : break;
5813 :
5814 384 : case DTK_TZ_MINUTE:
5815 384 : intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
5816 384 : break;
5817 :
5818 384 : case DTK_TZ_HOUR:
5819 384 : intresult = -tz / SECS_PER_HOUR;
5820 384 : break;
5821 :
5822 768 : case DTK_MICROSEC:
5823 768 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5824 768 : break;
5825 :
5826 768 : case DTK_MILLISEC:
5827 768 : if (retnumeric)
5828 : /*---
5829 : * tm->tm_sec * 1000 + fsec / 1000
5830 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5831 : */
5832 384 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5833 : else
5834 384 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5835 : break;
5836 :
5837 768 : case DTK_SECOND:
5838 768 : if (retnumeric)
5839 : /*---
5840 : * tm->tm_sec + fsec / 1'000'000
5841 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5842 : */
5843 384 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5844 : else
5845 384 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5846 : break;
5847 :
5848 384 : case DTK_MINUTE:
5849 384 : intresult = tm->tm_min;
5850 384 : break;
5851 :
5852 384 : case DTK_HOUR:
5853 384 : intresult = tm->tm_hour;
5854 384 : break;
5855 :
5856 384 : case DTK_DAY:
5857 384 : intresult = tm->tm_mday;
5858 384 : break;
5859 :
5860 384 : case DTK_MONTH:
5861 384 : intresult = tm->tm_mon;
5862 384 : break;
5863 :
5864 384 : case DTK_QUARTER:
5865 384 : intresult = (tm->tm_mon - 1) / 3 + 1;
5866 384 : break;
5867 :
5868 384 : case DTK_WEEK:
5869 384 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5870 384 : break;
5871 :
5872 408 : case DTK_YEAR:
5873 408 : if (tm->tm_year > 0)
5874 402 : intresult = tm->tm_year;
5875 : else
5876 : /* there is no year 0, just 1 BC and 1 AD */
5877 6 : intresult = tm->tm_year - 1;
5878 408 : break;
5879 :
5880 384 : case DTK_DECADE:
5881 : /* see comments in timestamp_part */
5882 384 : if (tm->tm_year > 0)
5883 378 : intresult = tm->tm_year / 10;
5884 : else
5885 6 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5886 384 : break;
5887 :
5888 384 : case DTK_CENTURY:
5889 : /* see comments in timestamp_part */
5890 384 : if (tm->tm_year > 0)
5891 378 : intresult = (tm->tm_year + 99) / 100;
5892 : else
5893 6 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5894 384 : break;
5895 :
5896 384 : case DTK_MILLENNIUM:
5897 : /* see comments in timestamp_part */
5898 384 : if (tm->tm_year > 0)
5899 378 : intresult = (tm->tm_year + 999) / 1000;
5900 : else
5901 6 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5902 384 : break;
5903 :
5904 768 : case DTK_JULIAN:
5905 768 : if (retnumeric)
5906 384 : PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5907 : 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),
5908 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5909 : NULL),
5910 : NULL));
5911 : else
5912 384 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5913 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5914 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5915 : break;
5916 :
5917 384 : case DTK_ISOYEAR:
5918 384 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5919 : /* Adjust BC years */
5920 384 : if (intresult <= 0)
5921 6 : intresult -= 1;
5922 384 : break;
5923 :
5924 828 : case DTK_DOW:
5925 : case DTK_ISODOW:
5926 828 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5927 828 : if (val == DTK_ISODOW && intresult == 0)
5928 18 : intresult = 7;
5929 828 : break;
5930 :
5931 384 : case DTK_DOY:
5932 384 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5933 384 : - date2j(tm->tm_year, 1, 1) + 1);
5934 384 : break;
5935 :
5936 0 : default:
5937 0 : ereport(ERROR,
5938 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5939 : errmsg("unit \"%s\" not supported for type %s",
5940 : lowunits, format_type_be(TIMESTAMPTZOID))));
5941 : intresult = 0;
5942 : }
5943 : }
5944 27460 : else if (type == RESERV)
5945 : {
5946 27460 : switch (val)
5947 : {
5948 27460 : case DTK_EPOCH:
5949 27460 : epoch = SetEpochTimestamp();
5950 : /* (timestamp - epoch) / 1000000 */
5951 27460 : if (retnumeric)
5952 : {
5953 : Numeric result;
5954 :
5955 27070 : if (timestamp < (PG_INT64_MAX + epoch))
5956 27064 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5957 : else
5958 : {
5959 6 : result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
5960 : int64_to_numeric(epoch),
5961 : NULL),
5962 : int64_to_numeric(1000000),
5963 : NULL);
5964 6 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5965 : NumericGetDatum(result),
5966 : Int32GetDatum(6)));
5967 : }
5968 27070 : PG_RETURN_NUMERIC(result);
5969 : }
5970 : else
5971 : {
5972 : float8 result;
5973 :
5974 : /* try to avoid precision loss in subtraction */
5975 390 : if (timestamp < (PG_INT64_MAX + epoch))
5976 384 : result = (timestamp - epoch) / 1000000.0;
5977 : else
5978 6 : result = ((float8) timestamp - epoch) / 1000000.0;
5979 390 : PG_RETURN_FLOAT8(result);
5980 : }
5981 : break;
5982 :
5983 0 : default:
5984 0 : ereport(ERROR,
5985 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5986 : errmsg("unit \"%s\" not supported for type %s",
5987 : lowunits, format_type_be(TIMESTAMPTZOID))));
5988 : intresult = 0;
5989 : }
5990 : }
5991 : else
5992 : {
5993 0 : ereport(ERROR,
5994 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5995 : errmsg("unit \"%s\" not recognized for type %s",
5996 : lowunits, format_type_be(TIMESTAMPTZOID))));
5997 :
5998 : intresult = 0;
5999 : }
6000 :
6001 7380 : if (retnumeric)
6002 468 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
6003 : else
6004 6912 : PG_RETURN_FLOAT8(intresult);
6005 : }
6006 :
6007 : Datum
6008 8718 : timestamptz_part(PG_FUNCTION_ARGS)
6009 : {
6010 8718 : return timestamptz_part_common(fcinfo, false);
6011 : }
6012 :
6013 : Datum
6014 28750 : extract_timestamptz(PG_FUNCTION_ARGS)
6015 : {
6016 28750 : return timestamptz_part_common(fcinfo, true);
6017 : }
6018 :
6019 : /*
6020 : * NonFiniteIntervalPart
6021 : *
6022 : * Used by interval_part when extracting from infinite interval. Returns
6023 : * +/-Infinity if that is the appropriate result, otherwise returns zero
6024 : * (which should be taken as meaning to return NULL).
6025 : *
6026 : * Errors thrown here for invalid units should exactly match those that
6027 : * would be thrown in the calling functions, else there will be unexpected
6028 : * discrepancies between finite- and infinite-input cases.
6029 : */
6030 : static float8
6031 384 : NonFiniteIntervalPart(int type, int unit, char *lowunits, bool isNegative)
6032 : {
6033 384 : if ((type != UNITS) && (type != RESERV))
6034 0 : ereport(ERROR,
6035 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6036 : errmsg("unit \"%s\" not recognized for type %s",
6037 : lowunits, format_type_be(INTERVALOID))));
6038 :
6039 384 : switch (unit)
6040 : {
6041 : /* Oscillating units */
6042 204 : case DTK_MICROSEC:
6043 : case DTK_MILLISEC:
6044 : case DTK_SECOND:
6045 : case DTK_MINUTE:
6046 : case DTK_WEEK:
6047 : case DTK_MONTH:
6048 : case DTK_QUARTER:
6049 204 : return 0.0;
6050 :
6051 : /* Monotonically-increasing units */
6052 180 : case DTK_HOUR:
6053 : case DTK_DAY:
6054 : case DTK_YEAR:
6055 : case DTK_DECADE:
6056 : case DTK_CENTURY:
6057 : case DTK_MILLENNIUM:
6058 : case DTK_EPOCH:
6059 180 : if (isNegative)
6060 90 : return -get_float8_infinity();
6061 : else
6062 90 : return get_float8_infinity();
6063 :
6064 0 : default:
6065 0 : ereport(ERROR,
6066 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6067 : errmsg("unit \"%s\" not supported for type %s",
6068 : lowunits, format_type_be(INTERVALOID))));
6069 : return 0.0; /* keep compiler quiet */
6070 : }
6071 : }
6072 :
6073 : /* interval_part() and extract_interval()
6074 : * Extract specified field from interval.
6075 : */
6076 : static Datum
6077 2376 : interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
6078 : {
6079 2376 : text *units = PG_GETARG_TEXT_PP(0);
6080 2376 : Interval *interval = PG_GETARG_INTERVAL_P(1);
6081 : int64 intresult;
6082 : int type,
6083 : val;
6084 : char *lowunits;
6085 : struct pg_itm tt,
6086 2376 : *tm = &tt;
6087 :
6088 2376 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
6089 2376 : VARSIZE_ANY_EXHDR(units),
6090 : false);
6091 :
6092 2376 : type = DecodeUnits(0, lowunits, &val);
6093 2376 : if (type == UNKNOWN_FIELD)
6094 234 : type = DecodeSpecial(0, lowunits, &val);
6095 :
6096 2376 : if (INTERVAL_NOT_FINITE(interval))
6097 : {
6098 384 : double r = NonFiniteIntervalPart(type, val, lowunits,
6099 384 : INTERVAL_IS_NOBEGIN(interval));
6100 :
6101 384 : if (r != 0.0)
6102 : {
6103 180 : if (retnumeric)
6104 : {
6105 168 : if (r < 0)
6106 84 : return DirectFunctionCall3(numeric_in,
6107 : CStringGetDatum("-Infinity"),
6108 : ObjectIdGetDatum(InvalidOid),
6109 : Int32GetDatum(-1));
6110 84 : else if (r > 0)
6111 84 : return DirectFunctionCall3(numeric_in,
6112 : CStringGetDatum("Infinity"),
6113 : ObjectIdGetDatum(InvalidOid),
6114 : Int32GetDatum(-1));
6115 : }
6116 : else
6117 12 : PG_RETURN_FLOAT8(r);
6118 : }
6119 : else
6120 204 : PG_RETURN_NULL();
6121 : }
6122 :
6123 1992 : if (type == UNITS)
6124 : {
6125 1794 : interval2itm(*interval, tm);
6126 1794 : switch (val)
6127 : {
6128 180 : case DTK_MICROSEC:
6129 180 : intresult = tm->tm_sec * INT64CONST(1000000) + tm->tm_usec;
6130 180 : break;
6131 :
6132 180 : case DTK_MILLISEC:
6133 180 : if (retnumeric)
6134 : /*---
6135 : * tm->tm_sec * 1000 + fsec / 1000
6136 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
6137 : */
6138 120 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 3));
6139 : else
6140 60 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + tm->tm_usec / 1000.0);
6141 : break;
6142 :
6143 180 : case DTK_SECOND:
6144 180 : if (retnumeric)
6145 : /*---
6146 : * tm->tm_sec + fsec / 1'000'000
6147 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
6148 : */
6149 120 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 6));
6150 : else
6151 60 : PG_RETURN_FLOAT8(tm->tm_sec + tm->tm_usec / 1000000.0);
6152 : break;
6153 :
6154 120 : case DTK_MINUTE:
6155 120 : intresult = tm->tm_min;
6156 120 : break;
6157 :
6158 120 : case DTK_HOUR:
6159 120 : intresult = tm->tm_hour;
6160 120 : break;
6161 :
6162 120 : case DTK_DAY:
6163 120 : intresult = tm->tm_mday;
6164 120 : break;
6165 :
6166 120 : case DTK_WEEK:
6167 120 : intresult = tm->tm_mday / 7;
6168 120 : break;
6169 :
6170 120 : case DTK_MONTH:
6171 120 : intresult = tm->tm_mon;
6172 120 : break;
6173 :
6174 120 : case DTK_QUARTER:
6175 :
6176 : /*
6177 : * We want to maintain the rule that a field extracted from a
6178 : * negative interval is the negative of the field's value for
6179 : * the sign-reversed interval. The broken-down tm_year and
6180 : * tm_mon aren't very helpful for that, so work from
6181 : * interval->month.
6182 : */
6183 120 : if (interval->month >= 0)
6184 90 : intresult = (tm->tm_mon / 3) + 1;
6185 : else
6186 30 : intresult = -(((-interval->month % MONTHS_PER_YEAR) / 3) + 1);
6187 120 : break;
6188 :
6189 120 : case DTK_YEAR:
6190 120 : intresult = tm->tm_year;
6191 120 : break;
6192 :
6193 144 : case DTK_DECADE:
6194 : /* caution: C division may have negative remainder */
6195 144 : intresult = tm->tm_year / 10;
6196 144 : break;
6197 :
6198 144 : case DTK_CENTURY:
6199 : /* caution: C division may have negative remainder */
6200 144 : intresult = tm->tm_year / 100;
6201 144 : break;
6202 :
6203 120 : case DTK_MILLENNIUM:
6204 : /* caution: C division may have negative remainder */
6205 120 : intresult = tm->tm_year / 1000;
6206 120 : break;
6207 :
6208 6 : default:
6209 6 : ereport(ERROR,
6210 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6211 : errmsg("unit \"%s\" not supported for type %s",
6212 : lowunits, format_type_be(INTERVALOID))));
6213 : intresult = 0;
6214 : }
6215 : }
6216 198 : else if (type == RESERV && val == DTK_EPOCH)
6217 : {
6218 192 : if (retnumeric)
6219 : {
6220 : Numeric result;
6221 : int64 secs_from_day_month;
6222 : int64 val;
6223 :
6224 : /*
6225 : * To do this calculation in integer arithmetic even though
6226 : * DAYS_PER_YEAR is fractional, multiply everything by 4 and then
6227 : * divide by 4 again at the end. This relies on DAYS_PER_YEAR
6228 : * being a multiple of 0.25 and on SECS_PER_DAY being a multiple
6229 : * of 4.
6230 : */
6231 132 : secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) +
6232 132 : (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) +
6233 132 : (int64) 4 * interval->day) * (SECS_PER_DAY / 4);
6234 :
6235 : /*---
6236 : * result = secs_from_day_month + interval->time / 1'000'000
6237 : * = (secs_from_day_month * 1'000'000 + interval->time) / 1'000'000
6238 : */
6239 :
6240 : /*
6241 : * Try the computation inside int64; if it overflows, do it in
6242 : * numeric (slower). This overflow happens around 10^9 days, so
6243 : * not common in practice.
6244 : */
6245 132 : if (!pg_mul_s64_overflow(secs_from_day_month, 1000000, &val) &&
6246 126 : !pg_add_s64_overflow(val, interval->time, &val))
6247 126 : result = int64_div_fast_to_numeric(val, 6);
6248 : else
6249 : result =
6250 6 : numeric_add_opt_error(int64_div_fast_to_numeric(interval->time, 6),
6251 : int64_to_numeric(secs_from_day_month),
6252 : NULL);
6253 :
6254 132 : PG_RETURN_NUMERIC(result);
6255 : }
6256 : else
6257 : {
6258 : float8 result;
6259 :
6260 60 : result = interval->time / 1000000.0;
6261 60 : result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
6262 60 : result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
6263 60 : result += ((double) SECS_PER_DAY) * interval->day;
6264 :
6265 60 : PG_RETURN_FLOAT8(result);
6266 : }
6267 : }
6268 : else
6269 : {
6270 6 : ereport(ERROR,
6271 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6272 : errmsg("unit \"%s\" not recognized for type %s",
6273 : lowunits, format_type_be(INTERVALOID))));
6274 : intresult = 0;
6275 : }
6276 :
6277 1428 : if (retnumeric)
6278 1368 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
6279 : else
6280 60 : PG_RETURN_FLOAT8(intresult);
6281 : }
6282 :
6283 : Datum
6284 288 : interval_part(PG_FUNCTION_ARGS)
6285 : {
6286 288 : return interval_part_common(fcinfo, false);
6287 : }
6288 :
6289 : Datum
6290 2088 : extract_interval(PG_FUNCTION_ARGS)
6291 : {
6292 2088 : return interval_part_common(fcinfo, true);
6293 : }
6294 :
6295 :
6296 : /* timestamp_zone()
6297 : * Encode timestamp type with specified time zone.
6298 : * This function is just timestamp2timestamptz() except instead of
6299 : * shifting to the global timezone, we shift to the specified timezone.
6300 : * This is different from the other AT TIME ZONE cases because instead
6301 : * of shifting _to_ a new time zone, it sets the time to _be_ the
6302 : * specified timezone.
6303 : */
6304 : Datum
6305 168 : timestamp_zone(PG_FUNCTION_ARGS)
6306 : {
6307 168 : text *zone = PG_GETARG_TEXT_PP(0);
6308 168 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6309 : TimestampTz result;
6310 : int tz;
6311 : char tzname[TZ_STRLEN_MAX + 1];
6312 : int type,
6313 : val;
6314 : pg_tz *tzp;
6315 : struct pg_tm tm;
6316 : fsec_t fsec;
6317 :
6318 168 : if (TIMESTAMP_NOT_FINITE(timestamp))
6319 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6320 :
6321 : /*
6322 : * Look up the requested timezone.
6323 : */
6324 168 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6325 :
6326 168 : type = DecodeTimezoneName(tzname, &val, &tzp);
6327 :
6328 168 : if (type == TZNAME_FIXED_OFFSET)
6329 : {
6330 : /* fixed-offset abbreviation */
6331 0 : tz = val;
6332 0 : result = dt2local(timestamp, tz);
6333 : }
6334 168 : else if (type == TZNAME_DYNTZ)
6335 : {
6336 : /* dynamic-offset abbreviation, resolve using specified time */
6337 84 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6338 0 : ereport(ERROR,
6339 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6340 : errmsg("timestamp out of range")));
6341 84 : tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
6342 84 : result = dt2local(timestamp, tz);
6343 : }
6344 : else
6345 : {
6346 : /* full zone name, rotate to that zone */
6347 84 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6348 0 : ereport(ERROR,
6349 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6350 : errmsg("timestamp out of range")));
6351 84 : tz = DetermineTimeZoneOffset(&tm, tzp);
6352 84 : if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
6353 0 : ereport(ERROR,
6354 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6355 : errmsg("timestamp out of range")));
6356 : }
6357 :
6358 168 : if (!IS_VALID_TIMESTAMP(result))
6359 0 : ereport(ERROR,
6360 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6361 : errmsg("timestamp out of range")));
6362 :
6363 168 : PG_RETURN_TIMESTAMPTZ(result);
6364 : }
6365 :
6366 : /* timestamp_izone()
6367 : * Encode timestamp type with specified time interval as time zone.
6368 : */
6369 : Datum
6370 12 : timestamp_izone(PG_FUNCTION_ARGS)
6371 : {
6372 12 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6373 12 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6374 : TimestampTz result;
6375 : int tz;
6376 :
6377 12 : if (TIMESTAMP_NOT_FINITE(timestamp))
6378 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6379 :
6380 12 : if (INTERVAL_NOT_FINITE(zone))
6381 12 : ereport(ERROR,
6382 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6383 : errmsg("interval time zone \"%s\" must be finite",
6384 : DatumGetCString(DirectFunctionCall1(interval_out,
6385 : PointerGetDatum(zone))))));
6386 :
6387 0 : if (zone->month != 0 || zone->day != 0)
6388 0 : ereport(ERROR,
6389 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6390 : errmsg("interval time zone \"%s\" must not include months or days",
6391 : DatumGetCString(DirectFunctionCall1(interval_out,
6392 : PointerGetDatum(zone))))));
6393 :
6394 0 : tz = zone->time / USECS_PER_SEC;
6395 :
6396 0 : result = dt2local(timestamp, tz);
6397 :
6398 0 : if (!IS_VALID_TIMESTAMP(result))
6399 0 : ereport(ERROR,
6400 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6401 : errmsg("timestamp out of range")));
6402 :
6403 0 : PG_RETURN_TIMESTAMPTZ(result);
6404 : } /* timestamp_izone() */
6405 :
6406 : /* TimestampTimestampTzRequiresRewrite()
6407 : *
6408 : * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
6409 : * timestamptz_timestamp to be no-ops, where the return value has the same
6410 : * bits as the argument. Since project convention is to assume a GUC changes
6411 : * no more often than STABLE functions change, the answer is valid that long.
6412 : */
6413 : bool
6414 18 : TimestampTimestampTzRequiresRewrite(void)
6415 : {
6416 : long offset;
6417 :
6418 18 : if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
6419 12 : return false;
6420 6 : return true;
6421 : }
6422 :
6423 : /* timestamp_timestamptz()
6424 : * Convert local timestamp to timestamp at GMT
6425 : */
6426 : Datum
6427 222 : timestamp_timestamptz(PG_FUNCTION_ARGS)
6428 : {
6429 222 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
6430 :
6431 222 : PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
6432 : }
6433 :
6434 : /*
6435 : * Convert timestamp to timestamp with time zone.
6436 : *
6437 : * On successful conversion, *overflow is set to zero if it's not NULL.
6438 : *
6439 : * If the timestamp is finite but out of the valid range for timestamptz, then:
6440 : * if overflow is NULL, we throw an out-of-range error.
6441 : * if overflow is not NULL, we store +1 or -1 there to indicate the sign
6442 : * of the overflow, and return the appropriate timestamptz infinity.
6443 : */
6444 : TimestampTz
6445 16320 : timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
6446 : {
6447 : TimestampTz result;
6448 : struct pg_tm tt,
6449 16320 : *tm = &tt;
6450 : fsec_t fsec;
6451 : int tz;
6452 :
6453 16320 : if (overflow)
6454 16086 : *overflow = 0;
6455 :
6456 16320 : if (TIMESTAMP_NOT_FINITE(timestamp))
6457 34 : return timestamp;
6458 :
6459 : /* timestamp2tm should not fail on valid timestamps, but cope */
6460 16286 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
6461 : {
6462 16286 : tz = DetermineTimeZoneOffset(tm, session_timezone);
6463 :
6464 16286 : result = dt2local(timestamp, -tz);
6465 :
6466 16286 : if (IS_VALID_TIMESTAMP(result))
6467 16274 : return result;
6468 : }
6469 :
6470 12 : if (overflow)
6471 : {
6472 12 : if (timestamp < 0)
6473 : {
6474 12 : *overflow = -1;
6475 12 : TIMESTAMP_NOBEGIN(result);
6476 : }
6477 : else
6478 : {
6479 0 : *overflow = 1;
6480 0 : TIMESTAMP_NOEND(result);
6481 : }
6482 12 : return result;
6483 : }
6484 :
6485 0 : ereport(ERROR,
6486 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6487 : errmsg("timestamp out of range")));
6488 :
6489 : return 0;
6490 : }
6491 :
6492 : /*
6493 : * Promote timestamp to timestamptz, throwing error for overflow.
6494 : */
6495 : static TimestampTz
6496 234 : timestamp2timestamptz(Timestamp timestamp)
6497 : {
6498 234 : return timestamp2timestamptz_opt_overflow(timestamp, NULL);
6499 : }
6500 :
6501 : /* timestamptz_timestamp()
6502 : * Convert timestamp at GMT to local timestamp
6503 : */
6504 : Datum
6505 62104 : timestamptz_timestamp(PG_FUNCTION_ARGS)
6506 : {
6507 62104 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
6508 :
6509 62104 : PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
6510 : }
6511 :
6512 : /*
6513 : * Convert timestamptz to timestamp, throwing error for overflow.
6514 : */
6515 : static Timestamp
6516 62170 : timestamptz2timestamp(TimestampTz timestamp)
6517 : {
6518 62170 : return timestamptz2timestamp_opt_overflow(timestamp, NULL);
6519 : }
6520 :
6521 : /*
6522 : * Convert timestamp with time zone to timestamp.
6523 : *
6524 : * On successful conversion, *overflow is set to zero if it's not NULL.
6525 : *
6526 : * If the timestamptz is finite but out of the valid range for timestamp, then:
6527 : * if overflow is NULL, we throw an out-of-range error.
6528 : * if overflow is not NULL, we store +1 or -1 there to indicate the sign
6529 : * of the overflow, and return the appropriate timestamp infinity.
6530 : */
6531 : Timestamp
6532 62210 : timestamptz2timestamp_opt_overflow(TimestampTz timestamp, int *overflow)
6533 : {
6534 : Timestamp result;
6535 : struct pg_tm tt,
6536 62210 : *tm = &tt;
6537 : fsec_t fsec;
6538 : int tz;
6539 :
6540 62210 : if (overflow)
6541 40 : *overflow = 0;
6542 :
6543 62210 : if (TIMESTAMP_NOT_FINITE(timestamp))
6544 24 : result = timestamp;
6545 : else
6546 : {
6547 62186 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
6548 : {
6549 0 : if (overflow)
6550 : {
6551 0 : if (timestamp < 0)
6552 : {
6553 0 : *overflow = -1;
6554 0 : TIMESTAMP_NOBEGIN(result);
6555 : }
6556 : else
6557 : {
6558 0 : *overflow = 1;
6559 0 : TIMESTAMP_NOEND(result);
6560 : }
6561 0 : return result;
6562 : }
6563 0 : ereport(ERROR,
6564 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6565 : errmsg("timestamp out of range")));
6566 : }
6567 62186 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
6568 : {
6569 4 : if (overflow)
6570 : {
6571 4 : if (timestamp < 0)
6572 : {
6573 4 : *overflow = -1;
6574 4 : TIMESTAMP_NOBEGIN(result);
6575 : }
6576 : else
6577 : {
6578 0 : *overflow = 1;
6579 0 : TIMESTAMP_NOEND(result);
6580 : }
6581 4 : return result;
6582 : }
6583 0 : ereport(ERROR,
6584 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6585 : errmsg("timestamp out of range")));
6586 : }
6587 : }
6588 62206 : return result;
6589 : }
6590 :
6591 : /* timestamptz_zone()
6592 : * Evaluate timestamp with time zone type at the specified time zone.
6593 : * Returns a timestamp without time zone.
6594 : */
6595 : Datum
6596 234 : timestamptz_zone(PG_FUNCTION_ARGS)
6597 : {
6598 234 : text *zone = PG_GETARG_TEXT_PP(0);
6599 234 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6600 : Timestamp result;
6601 : int tz;
6602 : char tzname[TZ_STRLEN_MAX + 1];
6603 : int type,
6604 : val;
6605 : pg_tz *tzp;
6606 :
6607 234 : if (TIMESTAMP_NOT_FINITE(timestamp))
6608 24 : PG_RETURN_TIMESTAMP(timestamp);
6609 :
6610 : /*
6611 : * Look up the requested timezone.
6612 : */
6613 210 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6614 :
6615 210 : type = DecodeTimezoneName(tzname, &val, &tzp);
6616 :
6617 204 : if (type == TZNAME_FIXED_OFFSET)
6618 : {
6619 : /* fixed-offset abbreviation */
6620 48 : tz = -val;
6621 48 : result = dt2local(timestamp, tz);
6622 : }
6623 156 : else if (type == TZNAME_DYNTZ)
6624 : {
6625 : /* dynamic-offset abbreviation, resolve using specified time */
6626 : int isdst;
6627 :
6628 72 : tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
6629 72 : result = dt2local(timestamp, tz);
6630 : }
6631 : else
6632 : {
6633 : /* full zone name, rotate from that zone */
6634 : struct pg_tm tm;
6635 : fsec_t fsec;
6636 :
6637 84 : if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
6638 0 : ereport(ERROR,
6639 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6640 : errmsg("timestamp out of range")));
6641 84 : if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
6642 0 : ereport(ERROR,
6643 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6644 : errmsg("timestamp out of range")));
6645 : }
6646 :
6647 204 : if (!IS_VALID_TIMESTAMP(result))
6648 0 : ereport(ERROR,
6649 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6650 : errmsg("timestamp out of range")));
6651 :
6652 204 : PG_RETURN_TIMESTAMP(result);
6653 : }
6654 :
6655 : /* timestamptz_izone()
6656 : * Encode timestamp with time zone type with specified time interval as time zone.
6657 : * Returns a timestamp without time zone.
6658 : */
6659 : Datum
6660 12 : timestamptz_izone(PG_FUNCTION_ARGS)
6661 : {
6662 12 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6663 12 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6664 : Timestamp result;
6665 : int tz;
6666 :
6667 12 : if (TIMESTAMP_NOT_FINITE(timestamp))
6668 0 : PG_RETURN_TIMESTAMP(timestamp);
6669 :
6670 12 : if (INTERVAL_NOT_FINITE(zone))
6671 12 : ereport(ERROR,
6672 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6673 : errmsg("interval time zone \"%s\" must be finite",
6674 : DatumGetCString(DirectFunctionCall1(interval_out,
6675 : PointerGetDatum(zone))))));
6676 :
6677 0 : if (zone->month != 0 || zone->day != 0)
6678 0 : ereport(ERROR,
6679 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6680 : errmsg("interval time zone \"%s\" must not include months or days",
6681 : DatumGetCString(DirectFunctionCall1(interval_out,
6682 : PointerGetDatum(zone))))));
6683 :
6684 0 : tz = -(zone->time / USECS_PER_SEC);
6685 :
6686 0 : result = dt2local(timestamp, tz);
6687 :
6688 0 : if (!IS_VALID_TIMESTAMP(result))
6689 0 : ereport(ERROR,
6690 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6691 : errmsg("timestamp out of range")));
6692 :
6693 0 : PG_RETURN_TIMESTAMP(result);
6694 : }
6695 :
6696 : /* generate_series_timestamp()
6697 : * Generate the set of timestamps from start to finish by step
6698 : */
6699 : Datum
6700 684 : generate_series_timestamp(PG_FUNCTION_ARGS)
6701 : {
6702 : FuncCallContext *funcctx;
6703 : generate_series_timestamp_fctx *fctx;
6704 : Timestamp result;
6705 :
6706 : /* stuff done only on the first call of the function */
6707 684 : if (SRF_IS_FIRSTCALL())
6708 : {
6709 42 : Timestamp start = PG_GETARG_TIMESTAMP(0);
6710 42 : Timestamp finish = PG_GETARG_TIMESTAMP(1);
6711 42 : Interval *step = PG_GETARG_INTERVAL_P(2);
6712 : MemoryContext oldcontext;
6713 :
6714 : /* create a function context for cross-call persistence */
6715 42 : funcctx = SRF_FIRSTCALL_INIT();
6716 :
6717 : /*
6718 : * switch to memory context appropriate for multiple function calls
6719 : */
6720 42 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6721 :
6722 : /* allocate memory for user context */
6723 : fctx = (generate_series_timestamp_fctx *)
6724 42 : palloc(sizeof(generate_series_timestamp_fctx));
6725 :
6726 : /*
6727 : * Use fctx to keep state from call to call. Seed current with the
6728 : * original start value
6729 : */
6730 42 : fctx->current = start;
6731 42 : fctx->finish = finish;
6732 42 : fctx->step = *step;
6733 :
6734 : /* Determine sign of the interval */
6735 42 : fctx->step_sign = interval_sign(&fctx->step);
6736 :
6737 42 : if (fctx->step_sign == 0)
6738 6 : ereport(ERROR,
6739 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6740 : errmsg("step size cannot equal zero")));
6741 :
6742 36 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6743 12 : ereport(ERROR,
6744 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6745 : errmsg("step size cannot be infinite")));
6746 :
6747 24 : funcctx->user_fctx = fctx;
6748 24 : MemoryContextSwitchTo(oldcontext);
6749 : }
6750 :
6751 : /* stuff done on every call of the function */
6752 666 : funcctx = SRF_PERCALL_SETUP();
6753 :
6754 : /*
6755 : * get the saved state and use current as the result for this iteration
6756 : */
6757 666 : fctx = funcctx->user_fctx;
6758 666 : result = fctx->current;
6759 :
6760 1332 : if (fctx->step_sign > 0 ?
6761 666 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6762 0 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6763 : {
6764 : /* increment current in preparation for next iteration */
6765 648 : fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
6766 : TimestampGetDatum(fctx->current),
6767 : PointerGetDatum(&fctx->step)));
6768 :
6769 : /* do when there is more left to send */
6770 648 : SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
6771 : }
6772 : else
6773 : {
6774 : /* do when there is no more left */
6775 18 : SRF_RETURN_DONE(funcctx);
6776 : }
6777 : }
6778 :
6779 : /* generate_series_timestamptz()
6780 : * Generate the set of timestamps from start to finish by step,
6781 : * doing arithmetic in the specified or session timezone.
6782 : */
6783 : static Datum
6784 62682 : generate_series_timestamptz_internal(FunctionCallInfo fcinfo)
6785 : {
6786 : FuncCallContext *funcctx;
6787 : generate_series_timestamptz_fctx *fctx;
6788 : TimestampTz result;
6789 :
6790 : /* stuff done only on the first call of the function */
6791 62682 : if (SRF_IS_FIRSTCALL())
6792 : {
6793 92 : TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
6794 92 : TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
6795 92 : Interval *step = PG_GETARG_INTERVAL_P(2);
6796 92 : text *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
6797 : MemoryContext oldcontext;
6798 :
6799 : /* create a function context for cross-call persistence */
6800 92 : funcctx = SRF_FIRSTCALL_INIT();
6801 :
6802 : /*
6803 : * switch to memory context appropriate for multiple function calls
6804 : */
6805 92 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6806 :
6807 : /* allocate memory for user context */
6808 : fctx = (generate_series_timestamptz_fctx *)
6809 92 : palloc(sizeof(generate_series_timestamptz_fctx));
6810 :
6811 : /*
6812 : * Use fctx to keep state from call to call. Seed current with the
6813 : * original start value
6814 : */
6815 92 : fctx->current = start;
6816 92 : fctx->finish = finish;
6817 92 : fctx->step = *step;
6818 92 : fctx->attimezone = zone ? lookup_timezone(zone) : session_timezone;
6819 :
6820 : /* Determine sign of the interval */
6821 92 : fctx->step_sign = interval_sign(&fctx->step);
6822 :
6823 92 : if (fctx->step_sign == 0)
6824 12 : ereport(ERROR,
6825 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6826 : errmsg("step size cannot equal zero")));
6827 :
6828 80 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6829 12 : ereport(ERROR,
6830 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6831 : errmsg("step size cannot be infinite")));
6832 :
6833 68 : funcctx->user_fctx = fctx;
6834 68 : MemoryContextSwitchTo(oldcontext);
6835 : }
6836 :
6837 : /* stuff done on every call of the function */
6838 62658 : funcctx = SRF_PERCALL_SETUP();
6839 :
6840 : /*
6841 : * get the saved state and use current as the result for this iteration
6842 : */
6843 62658 : fctx = funcctx->user_fctx;
6844 62658 : result = fctx->current;
6845 :
6846 125316 : if (fctx->step_sign > 0 ?
6847 62388 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6848 270 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6849 : {
6850 : /* increment current in preparation for next iteration */
6851 62596 : fctx->current = timestamptz_pl_interval_internal(fctx->current,
6852 : &fctx->step,
6853 : fctx->attimezone);
6854 :
6855 : /* do when there is more left to send */
6856 62596 : SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
6857 : }
6858 : else
6859 : {
6860 : /* do when there is no more left */
6861 62 : SRF_RETURN_DONE(funcctx);
6862 : }
6863 : }
6864 :
6865 : Datum
6866 62412 : generate_series_timestamptz(PG_FUNCTION_ARGS)
6867 : {
6868 62412 : return generate_series_timestamptz_internal(fcinfo);
6869 : }
6870 :
6871 : Datum
6872 270 : generate_series_timestamptz_at_zone(PG_FUNCTION_ARGS)
6873 : {
6874 270 : return generate_series_timestamptz_internal(fcinfo);
6875 : }
6876 :
6877 : /*
6878 : * Planner support function for generate_series(timestamp, timestamp, interval)
6879 : */
6880 : Datum
6881 396 : generate_series_timestamp_support(PG_FUNCTION_ARGS)
6882 : {
6883 396 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
6884 396 : Node *ret = NULL;
6885 :
6886 396 : if (IsA(rawreq, SupportRequestRows))
6887 : {
6888 : /* Try to estimate the number of rows returned */
6889 132 : SupportRequestRows *req = (SupportRequestRows *) rawreq;
6890 :
6891 132 : if (is_funcclause(req->node)) /* be paranoid */
6892 : {
6893 132 : List *args = ((FuncExpr *) req->node)->args;
6894 : Node *arg1,
6895 : *arg2,
6896 : *arg3;
6897 :
6898 : /* We can use estimated argument values here */
6899 132 : arg1 = estimate_expression_value(req->root, linitial(args));
6900 132 : arg2 = estimate_expression_value(req->root, lsecond(args));
6901 132 : arg3 = estimate_expression_value(req->root, lthird(args));
6902 :
6903 : /*
6904 : * If any argument is constant NULL, we can safely assume that
6905 : * zero rows are returned. Otherwise, if they're all non-NULL
6906 : * constants, we can calculate the number of rows that will be
6907 : * returned.
6908 : */
6909 132 : if ((IsA(arg1, Const) && ((Const *) arg1)->constisnull) ||
6910 132 : (IsA(arg2, Const) && ((Const *) arg2)->constisnull) ||
6911 132 : (IsA(arg3, Const) && ((Const *) arg3)->constisnull))
6912 : {
6913 0 : req->rows = 0;
6914 0 : ret = (Node *) req;
6915 : }
6916 132 : else if (IsA(arg1, Const) && IsA(arg2, Const) && IsA(arg3, Const))
6917 : {
6918 : Timestamp start,
6919 : finish;
6920 : Interval *step;
6921 : Datum diff;
6922 : double dstep;
6923 : int64 dummy;
6924 :
6925 130 : start = DatumGetTimestamp(((Const *) arg1)->constvalue);
6926 130 : finish = DatumGetTimestamp(((Const *) arg2)->constvalue);
6927 130 : step = DatumGetIntervalP(((Const *) arg3)->constvalue);
6928 :
6929 : /*
6930 : * Perform some prechecks which could cause timestamp_mi to
6931 : * raise an ERROR. It's much better to just return some
6932 : * default estimate than error out in a support function.
6933 : */
6934 130 : if (!TIMESTAMP_NOT_FINITE(start) && !TIMESTAMP_NOT_FINITE(finish) &&
6935 112 : !pg_sub_s64_overflow(finish, start, &dummy))
6936 : {
6937 112 : diff = DirectFunctionCall2(timestamp_mi,
6938 : TimestampGetDatum(finish),
6939 : TimestampGetDatum(start));
6940 :
6941 : #define INTERVAL_TO_MICROSECONDS(i) ((((double) (i)->month * DAYS_PER_MONTH + (i)->day)) * USECS_PER_DAY + (i)->time)
6942 :
6943 112 : dstep = INTERVAL_TO_MICROSECONDS(step);
6944 :
6945 : /* This equation works for either sign of step */
6946 112 : if (dstep != 0.0)
6947 : {
6948 94 : Interval *idiff = DatumGetIntervalP(diff);
6949 94 : double ddiff = INTERVAL_TO_MICROSECONDS(idiff);
6950 :
6951 94 : req->rows = floor(ddiff / dstep + 1.0);
6952 94 : ret = (Node *) req;
6953 : }
6954 : #undef INTERVAL_TO_MICROSECONDS
6955 : }
6956 : }
6957 : }
6958 : }
6959 :
6960 396 : PG_RETURN_POINTER(ret);
6961 : }
6962 :
6963 :
6964 : /* timestamp_at_local()
6965 : * timestamptz_at_local()
6966 : *
6967 : * The regression tests do not like two functions with the same proargs and
6968 : * prosrc but different proname, but the grammar for AT LOCAL needs an
6969 : * overloaded name to handle both types of timestamp, so we make simple
6970 : * wrappers for it.
6971 : */
6972 : Datum
6973 24 : timestamp_at_local(PG_FUNCTION_ARGS)
6974 : {
6975 24 : return timestamp_timestamptz(fcinfo);
6976 : }
6977 :
6978 : Datum
6979 24 : timestamptz_at_local(PG_FUNCTION_ARGS)
6980 : {
6981 24 : return timestamptz_timestamp(fcinfo);
6982 : }
|