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