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 636 : anytimestamp_typmod_check(bool istz, int32 typmod)
124 : {
125 636 : 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 636 : 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 636 : 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 17380 : timestamp_in(PG_FUNCTION_ARGS)
165 : {
166 17380 : char *str = PG_GETARG_CSTRING(0);
167 : #ifdef NOT_USED
168 : Oid typelem = PG_GETARG_OID(1);
169 : #endif
170 17380 : int32 typmod = PG_GETARG_INT32(2);
171 17380 : Node *escontext = fcinfo->context;
172 : Timestamp result;
173 : fsec_t fsec;
174 : struct pg_tm tt,
175 17380 : *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 17380 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
186 : field, ftype, MAXDATEFIELDS, &nf);
187 17380 : if (dterr == 0)
188 17380 : dterr = DecodeDateTime(field, ftype, nf,
189 : &dtype, tm, &fsec, &tz, &extra);
190 17380 : if (dterr != 0)
191 : {
192 114 : DateTimeParseError(dterr, &extra, str, "timestamp", escontext);
193 24 : PG_RETURN_NULL();
194 : }
195 :
196 17266 : switch (dtype)
197 : {
198 16930 : case DTK_DATE:
199 16930 : 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 16912 : 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 17248 : AdjustTimestampForTypmod(&result, typmod, escontext);
224 :
225 17248 : 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 124994 : 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 124994 : if (!TIMESTAMP_NOT_FINITE(*time)
389 124336 : && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
390 : {
391 63140 : 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 63140 : if (*time >= INT64CONST(0))
398 : {
399 62498 : *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
400 62498 : TimestampScales[typmod];
401 : }
402 : else
403 : {
404 642 : *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
405 642 : * TimestampScales[typmod]);
406 : }
407 : }
408 :
409 124994 : return true;
410 : }
411 :
412 : /* timestamptz_in()
413 : * Convert a string to internal form.
414 : */
415 : Datum
416 40924 : timestamptz_in(PG_FUNCTION_ARGS)
417 : {
418 40924 : char *str = PG_GETARG_CSTRING(0);
419 : #ifdef NOT_USED
420 : Oid typelem = PG_GETARG_OID(1);
421 : #endif
422 40924 : int32 typmod = PG_GETARG_INT32(2);
423 40924 : Node *escontext = fcinfo->context;
424 : TimestampTz result;
425 : fsec_t fsec;
426 : struct pg_tm tt,
427 40924 : *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 40924 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
438 : field, ftype, MAXDATEFIELDS, &nf);
439 40924 : if (dterr == 0)
440 40924 : dterr = DecodeDateTime(field, ftype, nf,
441 : &dtype, tm, &fsec, &tz, &extra);
442 40924 : if (dterr != 0)
443 : {
444 108 : DateTimeParseError(dterr, &extra, str, "timestamp with time zone",
445 : escontext);
446 24 : PG_RETURN_NULL();
447 : }
448 :
449 40816 : switch (dtype)
450 : {
451 40482 : case DTK_DATE:
452 40482 : 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 40458 : 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 40792 : AdjustTimestampForTypmod(&result, typmod, escontext);
477 :
478 40792 : 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 69520 : timestamptz_out(PG_FUNCTION_ARGS)
786 : {
787 69520 : TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
788 : char *result;
789 : int tz;
790 : struct pg_tm tt,
791 69520 : *tm = &tt;
792 : fsec_t fsec;
793 : const char *tzn;
794 : char buf[MAXDATELEN + 1];
795 :
796 69520 : if (TIMESTAMP_NOT_FINITE(dt))
797 728 : EncodeSpecialTimestamp(dt, buf);
798 68792 : else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
799 68792 : 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 69520 : result = pstrdup(buf);
806 69520 : 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 11772 : interval_in(PG_FUNCTION_ARGS)
901 : {
902 11772 : char *str = PG_GETARG_CSTRING(0);
903 : #ifdef NOT_USED
904 : Oid typelem = PG_GETARG_OID(1);
905 : #endif
906 11772 : int32 typmod = PG_GETARG_INT32(2);
907 11772 : Node *escontext = fcinfo->context;
908 : Interval *result;
909 : struct pg_itm_in tt,
910 11772 : *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 11772 : itm_in->tm_year = 0;
921 11772 : itm_in->tm_mon = 0;
922 11772 : itm_in->tm_mday = 0;
923 11772 : itm_in->tm_usec = 0;
924 :
925 11772 : if (typmod >= 0)
926 336 : range = INTERVAL_RANGE(typmod);
927 : else
928 11436 : range = INTERVAL_FULL_RANGE;
929 :
930 11772 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
931 : ftype, MAXDATEFIELDS, &nf);
932 11772 : if (dterr == 0)
933 11772 : 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 11772 : if (dterr == DTERR_BAD_FORMAT)
938 612 : dterr = DecodeISO8601Interval(str,
939 : &dtype, itm_in);
940 :
941 11772 : 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 10818 : result = (Interval *) palloc(sizeof(Interval));
950 :
951 10818 : switch (dtype)
952 : {
953 9846 : case DTK_DELTA:
954 9846 : 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 9828 : 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 10800 : AdjustIntervalForTypmod(result, typmod, escontext);
974 :
975 10788 : 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 11016 : 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 11016 : 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 9996 : 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 9984 : 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 7182876 : GetCurrentTimestamp(void)
1655 : {
1656 : TimestampTz result;
1657 : struct timeval tp;
1658 :
1659 7182876 : gettimeofday(&tp, NULL);
1660 :
1661 7182876 : result = (TimestampTz) tp.tv_sec -
1662 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1663 7182876 : result = (result * USECS_PER_SEC) + tp.tv_usec;
1664 :
1665 7182876 : return result;
1666 : }
1667 :
1668 : /*
1669 : * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
1670 : */
1671 : TimestampTz
1672 288 : GetSQLCurrentTimestamp(int32 typmod)
1673 : {
1674 : TimestampTz ts;
1675 :
1676 288 : ts = GetCurrentTransactionStartTimestamp();
1677 288 : if (typmod >= 0)
1678 12 : AdjustTimestampForTypmod(&ts, typmod, NULL);
1679 288 : 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 925568 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
1731 : long *secs, int *microsecs)
1732 : {
1733 925568 : TimestampTz diff = stop_time - start_time;
1734 :
1735 925568 : if (diff <= 0)
1736 : {
1737 140 : *secs = 0;
1738 140 : *microsecs = 0;
1739 : }
1740 : else
1741 : {
1742 925428 : *secs = (long) (diff / USECS_PER_SEC);
1743 925428 : *microsecs = (int) (diff % USECS_PER_SEC);
1744 : }
1745 925568 : }
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 292850 : TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
1767 : {
1768 : TimestampTz diff;
1769 :
1770 : /* Deal with zero or negative elapsed time quickly. */
1771 292850 : if (start_time >= stop_time)
1772 14 : return 0;
1773 : /* To not fail with timestamp infinities, we must detect overflow. */
1774 292836 : if (pg_sub_s64_overflow(stop_time, start_time, &diff))
1775 0 : return (long) INT_MAX;
1776 292836 : if (diff >= (INT_MAX * INT64CONST(1000) - 999))
1777 0 : return (long) INT_MAX;
1778 : else
1779 292836 : 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 962854 : TimestampDifferenceExceeds(TimestampTz start_time,
1791 : TimestampTz stop_time,
1792 : int msec)
1793 : {
1794 962854 : TimestampTz diff = stop_time - start_time;
1795 :
1796 962854 : 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 42604 : time_t_to_timestamptz(pg_time_t tm)
1812 : {
1813 : TimestampTz result;
1814 :
1815 42604 : result = (TimestampTz) tm -
1816 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
1817 42604 : result *= USECS_PER_SEC;
1818 :
1819 42604 : 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 35728 : timestamptz_to_time_t(TimestampTz t)
1834 : {
1835 : pg_time_t result;
1836 :
1837 35728 : result = (pg_time_t) (t / USECS_PER_SEC +
1838 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
1839 :
1840 35728 : 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 2426 : timestamptz_to_str(TimestampTz t)
1854 : {
1855 : static char buf[MAXDATELEN + 1];
1856 : int tz;
1857 : struct pg_tm tt,
1858 2426 : *tm = &tt;
1859 : fsec_t fsec;
1860 : const char *tzn;
1861 :
1862 2426 : if (TIMESTAMP_NOT_FINITE(t))
1863 0 : EncodeSpecialTimestamp(t, buf);
1864 2426 : else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
1865 2426 : EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1866 : else
1867 0 : strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1868 :
1869 2426 : return buf;
1870 : }
1871 :
1872 :
1873 : void
1874 253374 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
1875 : {
1876 : TimeOffset time;
1877 :
1878 253374 : time = jd;
1879 :
1880 253374 : *hour = time / USECS_PER_HOUR;
1881 253374 : time -= (*hour) * USECS_PER_HOUR;
1882 253374 : *min = time / USECS_PER_MINUTE;
1883 253374 : time -= (*min) * USECS_PER_MINUTE;
1884 253374 : *sec = time / USECS_PER_SEC;
1885 253374 : *fsec = time - (*sec * USECS_PER_SEC);
1886 253374 : } /* 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 253362 : 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 253362 : if (attimezone == NULL)
1909 235008 : attimezone = session_timezone;
1910 :
1911 253362 : time = dt;
1912 253362 : TMODULO(time, date, USECS_PER_DAY);
1913 :
1914 253362 : 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 253362 : date += POSTGRES_EPOCH_JDATE;
1922 :
1923 : /* Julian day routine does not work for negative Julian days */
1924 253362 : if (date < 0 || date > (Timestamp) INT_MAX)
1925 0 : return -1;
1926 :
1927 253362 : j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1928 253362 : dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
1929 :
1930 : /* Done if no TZ conversion wanted */
1931 253362 : 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 169866 : dt = (dt - *fsec) / USECS_PER_SEC +
1952 : (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1953 169866 : utime = (pg_time_t) dt;
1954 169866 : if ((Timestamp) utime == dt)
1955 : {
1956 169866 : struct pg_tm *tx = pg_localtime(&utime, attimezone);
1957 :
1958 169866 : tm->tm_year = tx->tm_year + 1900;
1959 169866 : tm->tm_mon = tx->tm_mon + 1;
1960 169866 : tm->tm_mday = tx->tm_mday;
1961 169866 : tm->tm_hour = tx->tm_hour;
1962 169866 : tm->tm_min = tx->tm_min;
1963 169866 : tm->tm_sec = tx->tm_sec;
1964 169866 : tm->tm_isdst = tx->tm_isdst;
1965 169866 : tm->tm_gmtoff = tx->tm_gmtoff;
1966 169866 : tm->tm_zone = tx->tm_zone;
1967 169866 : *tzp = -tm->tm_gmtoff;
1968 169866 : if (tzn != NULL)
1969 85406 : *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 169866 : 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 166178 : 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 166178 : 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 166166 : date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
2010 166166 : time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
2011 :
2012 166166 : *result = date * USECS_PER_DAY + time;
2013 : /* check for major overflow */
2014 166166 : 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 166160 : if ((*result < 0 && date > 0) ||
2022 166160 : (*result > 0 && date < -1))
2023 : {
2024 0 : *result = 0; /* keep compiler quiet */
2025 0 : return -1;
2026 : }
2027 166160 : if (tzp != NULL)
2028 50126 : *result = dt2local(*result, -(*tzp));
2029 :
2030 : /* final range check catches just-out-of-range timestamps */
2031 166160 : if (!IS_VALID_TIMESTAMP(*result))
2032 : {
2033 24 : *result = 0; /* keep compiler quiet */
2034 24 : return -1;
2035 : }
2036 :
2037 166136 : 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 22920 : itmin2interval(struct pg_itm_in *itm_in, Interval *span)
2116 : {
2117 22920 : int64 total_months = (int64) itm_in->tm_year * MONTHS_PER_YEAR + itm_in->tm_mon;
2118 :
2119 22920 : if (total_months > INT_MAX || total_months < INT_MIN)
2120 18 : return -1;
2121 22902 : span->month = (int32) total_months;
2122 22902 : span->day = itm_in->tm_mday;
2123 22902 : span->time = itm_in->tm_usec;
2124 22902 : return 0;
2125 : }
2126 :
2127 : static TimeOffset
2128 166166 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
2129 : {
2130 166166 : return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
2131 : }
2132 :
2133 : static Timestamp
2134 66608 : dt2local(Timestamp dt, int timezone)
2135 : {
2136 66608 : dt -= (timezone * USECS_PER_SEC);
2137 66608 : 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 404992 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
2211 : {
2212 404992 : return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2213 : }
2214 :
2215 : Datum
2216 30106 : timestamp_eq(PG_FUNCTION_ARGS)
2217 : {
2218 30106 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2219 30106 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2220 :
2221 30106 : 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 123836 : timestamp_lt(PG_FUNCTION_ARGS)
2235 : {
2236 123836 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2237 123836 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2238 :
2239 123836 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
2240 : }
2241 :
2242 : Datum
2243 98508 : timestamp_gt(PG_FUNCTION_ARGS)
2244 : {
2245 98508 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2246 98508 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2247 :
2248 98508 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
2249 : }
2250 :
2251 : Datum
2252 18478 : timestamp_le(PG_FUNCTION_ARGS)
2253 : {
2254 18478 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2255 18478 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2256 :
2257 18478 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
2258 : }
2259 :
2260 : Datum
2261 18542 : timestamp_ge(PG_FUNCTION_ARGS)
2262 : {
2263 18542 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2264 18542 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2265 :
2266 18542 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
2267 : }
2268 :
2269 : Datum
2270 35896 : timestamp_cmp(PG_FUNCTION_ARGS)
2271 : {
2272 35896 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2273 35896 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2274 :
2275 35896 : 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 438 : timestamp_sortsupport(PG_FUNCTION_ARGS)
2292 : {
2293 438 : 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 438 : ssup->comparator = ssup_datum_signed_cmp;
2302 : #else
2303 : ssup->comparator = timestamp_fastcmp;
2304 : #endif
2305 438 : 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 253086 : 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 253086 : days = interval->month * INT64CONST(30);
2493 253086 : days += interval->day;
2494 :
2495 : /* Widen time field to 128 bits */
2496 253086 : span = int64_to_int128(interval->time);
2497 :
2498 : /* Scale up days to microseconds, forming a 128-bit product */
2499 253086 : int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
2500 :
2501 253086 : return span;
2502 : }
2503 :
2504 : static int
2505 122954 : interval_cmp_internal(const Interval *interval1, const Interval *interval2)
2506 : {
2507 122954 : INT128 span1 = interval_cmp_value(interval1);
2508 122954 : INT128 span2 = interval_cmp_value(interval2);
2509 :
2510 122954 : 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 54286 : interval_cmp(PG_FUNCTION_ARGS)
2578 : {
2579 54286 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2580 54286 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
2581 :
2582 54286 : 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 6216 : timestamp_mi(PG_FUNCTION_ARGS)
2787 : {
2788 6216 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2789 6216 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
2790 : Interval *result;
2791 :
2792 6216 : 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 6216 : 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 6132 : 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 6120 : result->month = 0;
2834 6120 : 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 6120 : result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2862 : IntervalPGetDatum(result)));
2863 :
2864 6120 : 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 8124 : interval_justify_hours(PG_FUNCTION_ARGS)
2961 : {
2962 8124 : Interval *span = PG_GETARG_INTERVAL_P(0);
2963 : Interval *result;
2964 : TimeOffset wholeday;
2965 :
2966 8124 : result = (Interval *) palloc(sizeof(Interval));
2967 8124 : result->month = span->month;
2968 8124 : result->day = span->day;
2969 8124 : result->time = span->time;
2970 :
2971 : /* do nothing for infinite intervals */
2972 8124 : if (INTERVAL_NOT_FINITE(result))
2973 12 : PG_RETURN_INTERVAL_P(result);
2974 :
2975 8112 : TMODULO(result->time, wholeday, USECS_PER_DAY);
2976 8112 : 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 8106 : if (result->day > 0 && result->time < 0)
2982 : {
2983 0 : result->time += USECS_PER_DAY;
2984 0 : result->day--;
2985 : }
2986 8106 : else if (result->day < 0 && result->time > 0)
2987 : {
2988 0 : result->time -= USECS_PER_DAY;
2989 0 : result->day++;
2990 : }
2991 :
2992 8106 : 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 9602 : timestamp_pl_interval(PG_FUNCTION_ARGS)
3050 : {
3051 9602 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3052 9602 : 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 9602 : 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 9326 : 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 9122 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3080 114 : result = timestamp;
3081 : else
3082 : {
3083 9008 : 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 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3095 0 : ereport(ERROR,
3096 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3097 : errmsg("timestamp out of range")));
3098 2628 : if (tm->tm_mon > MONTHS_PER_YEAR)
3099 : {
3100 1398 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3101 1398 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3102 : }
3103 1230 : else if (tm->tm_mon < 1)
3104 : {
3105 1170 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3106 1170 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3107 : }
3108 :
3109 : /* adjust for end of month boundary problems... */
3110 2628 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3111 12 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3112 :
3113 2628 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3114 0 : ereport(ERROR,
3115 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3116 : errmsg("timestamp out of range")));
3117 : }
3118 :
3119 9008 : if (span->day != 0)
3120 : {
3121 : struct pg_tm tt,
3122 2904 : *tm = &tt;
3123 : fsec_t fsec;
3124 : int julian;
3125 :
3126 2904 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
3127 0 : ereport(ERROR,
3128 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3129 : errmsg("timestamp out of range")));
3130 :
3131 : /*
3132 : * Add days by converting to and from Julian. We need an overflow
3133 : * check here since j2date expects a non-negative integer input.
3134 : */
3135 2904 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3136 2904 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3137 2904 : julian < 0)
3138 6 : ereport(ERROR,
3139 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3140 : errmsg("timestamp out of range")));
3141 2898 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3142 :
3143 2898 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
3144 0 : ereport(ERROR,
3145 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3146 : errmsg("timestamp out of range")));
3147 : }
3148 :
3149 9002 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3150 6 : ereport(ERROR,
3151 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3152 : errmsg("timestamp out of range")));
3153 :
3154 8996 : if (!IS_VALID_TIMESTAMP(timestamp))
3155 0 : ereport(ERROR,
3156 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3157 : errmsg("timestamp out of range")));
3158 :
3159 8996 : result = timestamp;
3160 : }
3161 :
3162 9542 : PG_RETURN_TIMESTAMP(result);
3163 : }
3164 :
3165 : Datum
3166 2172 : timestamp_mi_interval(PG_FUNCTION_ARGS)
3167 : {
3168 2172 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
3169 2172 : Interval *span = PG_GETARG_INTERVAL_P(1);
3170 : Interval tspan;
3171 :
3172 2172 : interval_um_internal(span, &tspan);
3173 :
3174 2172 : return DirectFunctionCall2(timestamp_pl_interval,
3175 : TimestampGetDatum(timestamp),
3176 : PointerGetDatum(&tspan));
3177 : }
3178 :
3179 :
3180 : /* timestamptz_pl_interval_internal()
3181 : * Add an interval to a timestamptz, in the given (or session) timezone.
3182 : *
3183 : * Note that interval has provisions for qualitative year/month and day
3184 : * units, so try to do the right thing with them.
3185 : * To add a month, increment the month, and use the same day of month.
3186 : * Then, if the next month has fewer days, set the day of month
3187 : * to the last day of month.
3188 : * To add a day, increment the mday, and use the same time of day.
3189 : * Lastly, add in the "quantitative time".
3190 : */
3191 : static TimestampTz
3192 97890 : timestamptz_pl_interval_internal(TimestampTz timestamp,
3193 : Interval *span,
3194 : pg_tz *attimezone)
3195 : {
3196 : TimestampTz result;
3197 : int tz;
3198 :
3199 : /*
3200 : * Handle infinities.
3201 : *
3202 : * We treat anything that amounts to "infinity - infinity" as an error,
3203 : * since the timestamptz type has nothing equivalent to NaN.
3204 : */
3205 97890 : if (INTERVAL_IS_NOBEGIN(span))
3206 : {
3207 432 : if (TIMESTAMP_IS_NOEND(timestamp))
3208 12 : ereport(ERROR,
3209 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3210 : errmsg("timestamp out of range")));
3211 : else
3212 420 : TIMESTAMP_NOBEGIN(result);
3213 : }
3214 97458 : else if (INTERVAL_IS_NOEND(span))
3215 : {
3216 360 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
3217 12 : ereport(ERROR,
3218 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3219 : errmsg("timestamp out of range")));
3220 : else
3221 348 : TIMESTAMP_NOEND(result);
3222 : }
3223 97098 : else if (TIMESTAMP_NOT_FINITE(timestamp))
3224 120 : result = timestamp;
3225 : else
3226 : {
3227 : /* Use session timezone if caller asks for default */
3228 96978 : if (attimezone == NULL)
3229 34940 : attimezone = session_timezone;
3230 :
3231 96978 : if (span->month != 0)
3232 : {
3233 : struct pg_tm tt,
3234 2340 : *tm = &tt;
3235 : fsec_t fsec;
3236 :
3237 2340 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3238 0 : ereport(ERROR,
3239 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3240 : errmsg("timestamp out of range")));
3241 :
3242 2340 : if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
3243 0 : ereport(ERROR,
3244 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3245 : errmsg("timestamp out of range")));
3246 2340 : if (tm->tm_mon > MONTHS_PER_YEAR)
3247 : {
3248 894 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
3249 894 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
3250 : }
3251 1446 : else if (tm->tm_mon < 1)
3252 : {
3253 1020 : tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
3254 1020 : tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
3255 : }
3256 :
3257 : /* adjust for end of month boundary problems... */
3258 2340 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
3259 54 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3260 :
3261 2340 : tz = DetermineTimeZoneOffset(tm, attimezone);
3262 :
3263 2340 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3264 0 : ereport(ERROR,
3265 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3266 : errmsg("timestamp out of range")));
3267 : }
3268 :
3269 96978 : if (span->day != 0)
3270 : {
3271 : struct pg_tm tt,
3272 3068 : *tm = &tt;
3273 : fsec_t fsec;
3274 : int julian;
3275 :
3276 3068 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
3277 0 : ereport(ERROR,
3278 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3279 : errmsg("timestamp out of range")));
3280 :
3281 : /*
3282 : * Add days by converting to and from Julian. We need an overflow
3283 : * check here since j2date expects a non-negative integer input.
3284 : * In practice though, it will give correct answers for small
3285 : * negative Julian dates; we should allow -1 to avoid
3286 : * timezone-dependent failures, as discussed in timestamp.h.
3287 : */
3288 3068 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3289 3068 : if (pg_add_s32_overflow(julian, span->day, &julian) ||
3290 3068 : julian < -1)
3291 6 : ereport(ERROR,
3292 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3293 : errmsg("timestamp out of range")));
3294 3062 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3295 :
3296 3062 : tz = DetermineTimeZoneOffset(tm, attimezone);
3297 :
3298 3062 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
3299 0 : ereport(ERROR,
3300 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3301 : errmsg("timestamp out of range")));
3302 : }
3303 :
3304 96972 : if (pg_add_s64_overflow(timestamp, span->time, ×tamp))
3305 6 : ereport(ERROR,
3306 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3307 : errmsg("timestamp out of range")));
3308 :
3309 96966 : if (!IS_VALID_TIMESTAMP(timestamp))
3310 0 : ereport(ERROR,
3311 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3312 : errmsg("timestamp out of range")));
3313 :
3314 96966 : result = timestamp;
3315 : }
3316 :
3317 97854 : return result;
3318 : }
3319 :
3320 : /* timestamptz_mi_interval_internal()
3321 : * As above, but subtract the interval.
3322 : */
3323 : static TimestampTz
3324 2118 : timestamptz_mi_interval_internal(TimestampTz timestamp,
3325 : Interval *span,
3326 : pg_tz *attimezone)
3327 : {
3328 : Interval tspan;
3329 :
3330 2118 : interval_um_internal(span, &tspan);
3331 :
3332 2118 : return timestamptz_pl_interval_internal(timestamp, &tspan, attimezone);
3333 : }
3334 :
3335 : /* timestamptz_pl_interval()
3336 : * Add an interval to a timestamptz, in the session timezone.
3337 : */
3338 : Datum
3339 33326 : timestamptz_pl_interval(PG_FUNCTION_ARGS)
3340 : {
3341 33326 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3342 33326 : Interval *span = PG_GETARG_INTERVAL_P(1);
3343 :
3344 33326 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, NULL));
3345 : }
3346 :
3347 : Datum
3348 1632 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
3349 : {
3350 1632 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3351 1632 : Interval *span = PG_GETARG_INTERVAL_P(1);
3352 :
3353 1632 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, NULL));
3354 : }
3355 :
3356 : /* timestamptz_pl_interval_at_zone()
3357 : * Add an interval to a timestamptz, in the specified timezone.
3358 : */
3359 : Datum
3360 6 : timestamptz_pl_interval_at_zone(PG_FUNCTION_ARGS)
3361 : {
3362 6 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3363 6 : Interval *span = PG_GETARG_INTERVAL_P(1);
3364 6 : text *zone = PG_GETARG_TEXT_PP(2);
3365 6 : pg_tz *attimezone = lookup_timezone(zone);
3366 :
3367 6 : PG_RETURN_TIMESTAMP(timestamptz_pl_interval_internal(timestamp, span, attimezone));
3368 : }
3369 :
3370 : Datum
3371 6 : timestamptz_mi_interval_at_zone(PG_FUNCTION_ARGS)
3372 : {
3373 6 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3374 6 : Interval *span = PG_GETARG_INTERVAL_P(1);
3375 6 : text *zone = PG_GETARG_TEXT_PP(2);
3376 6 : pg_tz *attimezone = lookup_timezone(zone);
3377 :
3378 6 : PG_RETURN_TIMESTAMP(timestamptz_mi_interval_internal(timestamp, span, attimezone));
3379 : }
3380 :
3381 : /* interval_um_internal()
3382 : * Negate an interval.
3383 : */
3384 : static void
3385 6960 : interval_um_internal(const Interval *interval, Interval *result)
3386 : {
3387 6960 : if (INTERVAL_IS_NOBEGIN(interval))
3388 180 : INTERVAL_NOEND(result);
3389 6780 : else if (INTERVAL_IS_NOEND(interval))
3390 588 : INTERVAL_NOBEGIN(result);
3391 : else
3392 : {
3393 : /* Negate each field, guarding against overflow */
3394 12378 : if (pg_sub_s64_overflow(INT64CONST(0), interval->time, &result->time) ||
3395 12366 : pg_sub_s32_overflow(0, interval->day, &result->day) ||
3396 6180 : pg_sub_s32_overflow(0, interval->month, &result->month) ||
3397 6174 : INTERVAL_NOT_FINITE(result))
3398 30 : ereport(ERROR,
3399 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3400 : errmsg("interval out of range")));
3401 : }
3402 6930 : }
3403 :
3404 : Datum
3405 2634 : interval_um(PG_FUNCTION_ARGS)
3406 : {
3407 2634 : Interval *interval = PG_GETARG_INTERVAL_P(0);
3408 : Interval *result;
3409 :
3410 2634 : result = (Interval *) palloc(sizeof(Interval));
3411 2634 : interval_um_internal(interval, result);
3412 :
3413 2604 : PG_RETURN_INTERVAL_P(result);
3414 : }
3415 :
3416 :
3417 : Datum
3418 0 : interval_smaller(PG_FUNCTION_ARGS)
3419 : {
3420 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3421 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3422 : Interval *result;
3423 :
3424 : /* use interval_cmp_internal to be sure this agrees with comparisons */
3425 0 : if (interval_cmp_internal(interval1, interval2) < 0)
3426 0 : result = interval1;
3427 : else
3428 0 : result = interval2;
3429 0 : PG_RETURN_INTERVAL_P(result);
3430 : }
3431 :
3432 : Datum
3433 0 : interval_larger(PG_FUNCTION_ARGS)
3434 : {
3435 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
3436 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
3437 : Interval *result;
3438 :
3439 0 : if (interval_cmp_internal(interval1, interval2) > 0)
3440 0 : result = interval1;
3441 : else
3442 0 : result = interval2;
3443 0 : PG_RETURN_INTERVAL_P(result);
3444 : }
3445 :
3446 : static void
3447 528 : finite_interval_pl(const Interval *span1, const Interval *span2, Interval *result)
3448 : {
3449 : Assert(!INTERVAL_NOT_FINITE(span1));
3450 : Assert(!INTERVAL_NOT_FINITE(span2));
3451 :
3452 1056 : if (pg_add_s32_overflow(span1->month, span2->month, &result->month) ||
3453 1056 : pg_add_s32_overflow(span1->day, span2->day, &result->day) ||
3454 528 : pg_add_s64_overflow(span1->time, span2->time, &result->time) ||
3455 528 : INTERVAL_NOT_FINITE(result))
3456 12 : ereport(ERROR,
3457 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3458 : errmsg("interval out of range")));
3459 516 : }
3460 :
3461 : Datum
3462 558 : interval_pl(PG_FUNCTION_ARGS)
3463 : {
3464 558 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3465 558 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3466 : Interval *result;
3467 :
3468 558 : result = (Interval *) palloc(sizeof(Interval));
3469 :
3470 : /*
3471 : * Handle infinities.
3472 : *
3473 : * We treat anything that amounts to "infinity - infinity" as an error,
3474 : * since the interval type has nothing equivalent to NaN.
3475 : */
3476 558 : if (INTERVAL_IS_NOBEGIN(span1))
3477 : {
3478 54 : if (INTERVAL_IS_NOEND(span2))
3479 6 : ereport(ERROR,
3480 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3481 : errmsg("interval out of range")));
3482 : else
3483 48 : INTERVAL_NOBEGIN(result);
3484 : }
3485 504 : else if (INTERVAL_IS_NOEND(span1))
3486 : {
3487 42 : if (INTERVAL_IS_NOBEGIN(span2))
3488 6 : ereport(ERROR,
3489 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3490 : errmsg("interval out of range")));
3491 : else
3492 36 : INTERVAL_NOEND(result);
3493 : }
3494 462 : else if (INTERVAL_NOT_FINITE(span2))
3495 138 : memcpy(result, span2, sizeof(Interval));
3496 : else
3497 324 : finite_interval_pl(span1, span2, result);
3498 :
3499 534 : PG_RETURN_INTERVAL_P(result);
3500 : }
3501 :
3502 : static void
3503 1548 : finite_interval_mi(const Interval *span1, const Interval *span2, Interval *result)
3504 : {
3505 : Assert(!INTERVAL_NOT_FINITE(span1));
3506 : Assert(!INTERVAL_NOT_FINITE(span2));
3507 :
3508 3096 : if (pg_sub_s32_overflow(span1->month, span2->month, &result->month) ||
3509 3096 : pg_sub_s32_overflow(span1->day, span2->day, &result->day) ||
3510 1548 : pg_sub_s64_overflow(span1->time, span2->time, &result->time) ||
3511 1548 : INTERVAL_NOT_FINITE(result))
3512 12 : ereport(ERROR,
3513 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3514 : errmsg("interval out of range")));
3515 1536 : }
3516 :
3517 : Datum
3518 1794 : interval_mi(PG_FUNCTION_ARGS)
3519 : {
3520 1794 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
3521 1794 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
3522 : Interval *result;
3523 :
3524 1794 : result = (Interval *) palloc(sizeof(Interval));
3525 :
3526 : /*
3527 : * Handle infinities.
3528 : *
3529 : * We treat anything that amounts to "infinity - infinity" as an error,
3530 : * since the interval type has nothing equivalent to NaN.
3531 : */
3532 1794 : if (INTERVAL_IS_NOBEGIN(span1))
3533 : {
3534 54 : if (INTERVAL_IS_NOBEGIN(span2))
3535 6 : ereport(ERROR,
3536 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3537 : errmsg("interval out of range")));
3538 : else
3539 48 : INTERVAL_NOBEGIN(result);
3540 : }
3541 1740 : else if (INTERVAL_IS_NOEND(span1))
3542 : {
3543 48 : if (INTERVAL_IS_NOEND(span2))
3544 6 : ereport(ERROR,
3545 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3546 : errmsg("interval out of range")));
3547 : else
3548 42 : INTERVAL_NOEND(result);
3549 : }
3550 1692 : else if (INTERVAL_IS_NOBEGIN(span2))
3551 6 : INTERVAL_NOEND(result);
3552 1686 : else if (INTERVAL_IS_NOEND(span2))
3553 186 : INTERVAL_NOBEGIN(result);
3554 : else
3555 1500 : finite_interval_mi(span1, span2, result);
3556 :
3557 1770 : PG_RETURN_INTERVAL_P(result);
3558 : }
3559 :
3560 : /*
3561 : * There is no interval_abs(): it is unclear what value to return:
3562 : * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3563 : * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3564 : */
3565 :
3566 : Datum
3567 11652 : interval_mul(PG_FUNCTION_ARGS)
3568 : {
3569 11652 : Interval *span = PG_GETARG_INTERVAL_P(0);
3570 11652 : float8 factor = PG_GETARG_FLOAT8(1);
3571 : double month_remainder_days,
3572 : sec_remainder,
3573 : result_double;
3574 11652 : int32 orig_month = span->month,
3575 11652 : orig_day = span->day;
3576 : Interval *result;
3577 :
3578 11652 : result = (Interval *) palloc(sizeof(Interval));
3579 :
3580 : /*
3581 : * Handle NaN and infinities.
3582 : *
3583 : * We treat "0 * infinity" and "infinity * 0" as errors, since the
3584 : * interval type has nothing equivalent to NaN.
3585 : */
3586 11652 : if (isnan(factor))
3587 12 : goto out_of_range;
3588 :
3589 11640 : if (INTERVAL_NOT_FINITE(span))
3590 : {
3591 60 : if (factor == 0.0)
3592 12 : goto out_of_range;
3593 :
3594 48 : if (factor < 0.0)
3595 24 : interval_um_internal(span, result);
3596 : else
3597 24 : memcpy(result, span, sizeof(Interval));
3598 :
3599 48 : PG_RETURN_INTERVAL_P(result);
3600 : }
3601 11580 : if (isinf(factor))
3602 : {
3603 24 : int isign = interval_sign(span);
3604 :
3605 24 : if (isign == 0)
3606 12 : goto out_of_range;
3607 :
3608 12 : if (factor * isign < 0)
3609 6 : INTERVAL_NOBEGIN(result);
3610 : else
3611 6 : INTERVAL_NOEND(result);
3612 :
3613 12 : PG_RETURN_INTERVAL_P(result);
3614 : }
3615 :
3616 11556 : result_double = span->month * factor;
3617 11556 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3618 6 : goto out_of_range;
3619 11550 : result->month = (int32) result_double;
3620 :
3621 11550 : result_double = span->day * factor;
3622 11550 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3623 6 : goto out_of_range;
3624 11544 : result->day = (int32) result_double;
3625 :
3626 : /*
3627 : * The above correctly handles the whole-number part of the month and day
3628 : * products, but we have to do something with any fractional part
3629 : * resulting when the factor is non-integral. We cascade the fractions
3630 : * down to lower units using the conversion factors DAYS_PER_MONTH and
3631 : * SECS_PER_DAY. Note we do NOT cascade up, since we are not forced to do
3632 : * so by the representation. The user can choose to cascade up later,
3633 : * using justify_hours and/or justify_days.
3634 : */
3635 :
3636 : /*
3637 : * Fractional months full days into days.
3638 : *
3639 : * Floating point calculation are inherently imprecise, so these
3640 : * calculations are crafted to produce the most reliable result possible.
3641 : * TSROUND() is needed to more accurately produce whole numbers where
3642 : * appropriate.
3643 : */
3644 11544 : month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
3645 11544 : month_remainder_days = TSROUND(month_remainder_days);
3646 11544 : sec_remainder = (orig_day * factor - result->day +
3647 11544 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3648 11544 : sec_remainder = TSROUND(sec_remainder);
3649 :
3650 : /*
3651 : * Might have 24:00:00 hours due to rounding, or >24 hours because of time
3652 : * cascade from months and days. It might still be >24 if the combination
3653 : * of cascade and the seconds factor operation itself.
3654 : */
3655 11544 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3656 : {
3657 0 : if (pg_add_s32_overflow(result->day,
3658 0 : (int) (sec_remainder / SECS_PER_DAY),
3659 : &result->day))
3660 0 : goto out_of_range;
3661 0 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3662 : }
3663 :
3664 : /* cascade units down */
3665 11544 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3666 : &result->day))
3667 6 : goto out_of_range;
3668 11538 : result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
3669 11538 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3670 6 : goto out_of_range;
3671 11532 : result->time = (int64) result_double;
3672 :
3673 11532 : if (INTERVAL_NOT_FINITE(result))
3674 6 : goto out_of_range;
3675 :
3676 11526 : PG_RETURN_INTERVAL_P(result);
3677 :
3678 66 : out_of_range:
3679 66 : ereport(ERROR,
3680 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3681 : errmsg("interval out of range"));
3682 :
3683 : PG_RETURN_NULL(); /* keep compiler quiet */
3684 : }
3685 :
3686 : Datum
3687 11430 : mul_d_interval(PG_FUNCTION_ARGS)
3688 : {
3689 : /* Args are float8 and Interval *, but leave them as generic Datum */
3690 11430 : Datum factor = PG_GETARG_DATUM(0);
3691 11430 : Datum span = PG_GETARG_DATUM(1);
3692 :
3693 11430 : return DirectFunctionCall2(interval_mul, span, factor);
3694 : }
3695 :
3696 : Datum
3697 222 : interval_div(PG_FUNCTION_ARGS)
3698 : {
3699 222 : Interval *span = PG_GETARG_INTERVAL_P(0);
3700 222 : float8 factor = PG_GETARG_FLOAT8(1);
3701 : double month_remainder_days,
3702 : sec_remainder,
3703 : result_double;
3704 222 : int32 orig_month = span->month,
3705 222 : orig_day = span->day;
3706 : Interval *result;
3707 :
3708 222 : result = (Interval *) palloc(sizeof(Interval));
3709 :
3710 222 : if (factor == 0.0)
3711 0 : ereport(ERROR,
3712 : (errcode(ERRCODE_DIVISION_BY_ZERO),
3713 : errmsg("division by zero")));
3714 :
3715 : /*
3716 : * Handle NaN and infinities.
3717 : *
3718 : * We treat "infinity / infinity" as an error, since the interval type has
3719 : * nothing equivalent to NaN. Otherwise, dividing by infinity is handled
3720 : * by the regular division code, causing all fields to be set to zero.
3721 : */
3722 222 : if (isnan(factor))
3723 12 : goto out_of_range;
3724 :
3725 210 : if (INTERVAL_NOT_FINITE(span))
3726 : {
3727 48 : if (isinf(factor))
3728 24 : goto out_of_range;
3729 :
3730 24 : if (factor < 0.0)
3731 12 : interval_um_internal(span, result);
3732 : else
3733 12 : memcpy(result, span, sizeof(Interval));
3734 :
3735 24 : PG_RETURN_INTERVAL_P(result);
3736 : }
3737 :
3738 162 : result_double = span->month / factor;
3739 162 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3740 6 : goto out_of_range;
3741 156 : result->month = (int32) result_double;
3742 :
3743 156 : result_double = span->day / factor;
3744 156 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT32(result_double))
3745 6 : goto out_of_range;
3746 150 : result->day = (int32) result_double;
3747 :
3748 : /*
3749 : * Fractional months full days into days. See comment in interval_mul().
3750 : */
3751 150 : month_remainder_days = (orig_month / factor - result->month) * DAYS_PER_MONTH;
3752 150 : month_remainder_days = TSROUND(month_remainder_days);
3753 150 : sec_remainder = (orig_day / factor - result->day +
3754 150 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
3755 150 : sec_remainder = TSROUND(sec_remainder);
3756 150 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3757 : {
3758 6 : if (pg_add_s32_overflow(result->day,
3759 6 : (int) (sec_remainder / SECS_PER_DAY),
3760 : &result->day))
3761 0 : goto out_of_range;
3762 6 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
3763 : }
3764 :
3765 : /* cascade units down */
3766 150 : if (pg_add_s32_overflow(result->day, (int32) month_remainder_days,
3767 : &result->day))
3768 0 : goto out_of_range;
3769 150 : result_double = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
3770 150 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3771 6 : goto out_of_range;
3772 144 : result->time = (int64) result_double;
3773 :
3774 144 : if (INTERVAL_NOT_FINITE(result))
3775 6 : goto out_of_range;
3776 :
3777 138 : PG_RETURN_INTERVAL_P(result);
3778 :
3779 60 : out_of_range:
3780 60 : ereport(ERROR,
3781 : errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3782 : errmsg("interval out of range"));
3783 :
3784 : PG_RETURN_NULL(); /* keep compiler quiet */
3785 : }
3786 :
3787 :
3788 : /*
3789 : * in_range support functions for timestamps and intervals.
3790 : *
3791 : * Per SQL spec, we support these with interval as the offset type.
3792 : * The spec's restriction that the offset not be negative is a bit hard to
3793 : * decipher for intervals, but we choose to interpret it the same as our
3794 : * interval comparison operators would.
3795 : */
3796 :
3797 : Datum
3798 1134 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
3799 : {
3800 1134 : TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
3801 1134 : TimestampTz base = PG_GETARG_TIMESTAMPTZ(1);
3802 1134 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3803 1134 : bool sub = PG_GETARG_BOOL(3);
3804 1134 : bool less = PG_GETARG_BOOL(4);
3805 : TimestampTz sum;
3806 :
3807 1134 : if (interval_sign(offset) < 0)
3808 12 : ereport(ERROR,
3809 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3810 : errmsg("invalid preceding or following size in window function")));
3811 :
3812 : /*
3813 : * Deal with cases where both base and offset are infinite, and computing
3814 : * base +/- offset would cause an error. As for float and numeric types,
3815 : * we assume that all values infinitely precede +infinity and infinitely
3816 : * follow -infinity. See in_range_float8_float8() for reasoning.
3817 : */
3818 1122 : if (INTERVAL_IS_NOEND(offset) &&
3819 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3820 228 : PG_RETURN_BOOL(true);
3821 :
3822 : /* We don't currently bother to avoid overflow hazards here */
3823 894 : if (sub)
3824 480 : sum = timestamptz_mi_interval_internal(base, offset, NULL);
3825 : else
3826 414 : sum = timestamptz_pl_interval_internal(base, offset, NULL);
3827 :
3828 894 : if (less)
3829 354 : PG_RETURN_BOOL(val <= sum);
3830 : else
3831 540 : PG_RETURN_BOOL(val >= sum);
3832 : }
3833 :
3834 : Datum
3835 2466 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
3836 : {
3837 2466 : Timestamp val = PG_GETARG_TIMESTAMP(0);
3838 2466 : Timestamp base = PG_GETARG_TIMESTAMP(1);
3839 2466 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3840 2466 : bool sub = PG_GETARG_BOOL(3);
3841 2466 : bool less = PG_GETARG_BOOL(4);
3842 : Timestamp sum;
3843 :
3844 2466 : if (interval_sign(offset) < 0)
3845 18 : ereport(ERROR,
3846 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3847 : errmsg("invalid preceding or following size in window function")));
3848 :
3849 : /*
3850 : * Deal with cases where both base and offset are infinite, and computing
3851 : * base +/- offset would cause an error. As for float and numeric types,
3852 : * we assume that all values infinitely precede +infinity and infinitely
3853 : * follow -infinity. See in_range_float8_float8() for reasoning.
3854 : */
3855 2448 : if (INTERVAL_IS_NOEND(offset) &&
3856 : (sub ? TIMESTAMP_IS_NOEND(base) : TIMESTAMP_IS_NOBEGIN(base)))
3857 228 : PG_RETURN_BOOL(true);
3858 :
3859 : /* We don't currently bother to avoid overflow hazards here */
3860 2220 : if (sub)
3861 1032 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
3862 : TimestampGetDatum(base),
3863 : IntervalPGetDatum(offset)));
3864 : else
3865 1188 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
3866 : TimestampGetDatum(base),
3867 : IntervalPGetDatum(offset)));
3868 :
3869 2220 : if (less)
3870 1206 : PG_RETURN_BOOL(val <= sum);
3871 : else
3872 1014 : PG_RETURN_BOOL(val >= sum);
3873 : }
3874 :
3875 : Datum
3876 1128 : in_range_interval_interval(PG_FUNCTION_ARGS)
3877 : {
3878 1128 : Interval *val = PG_GETARG_INTERVAL_P(0);
3879 1128 : Interval *base = PG_GETARG_INTERVAL_P(1);
3880 1128 : Interval *offset = PG_GETARG_INTERVAL_P(2);
3881 1128 : bool sub = PG_GETARG_BOOL(3);
3882 1128 : bool less = PG_GETARG_BOOL(4);
3883 : Interval *sum;
3884 :
3885 1128 : if (interval_sign(offset) < 0)
3886 12 : ereport(ERROR,
3887 : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
3888 : errmsg("invalid preceding or following size in window function")));
3889 :
3890 : /*
3891 : * Deal with cases where both base and offset are infinite, and computing
3892 : * base +/- offset would cause an error. As for float and numeric types,
3893 : * we assume that all values infinitely precede +infinity and infinitely
3894 : * follow -infinity. See in_range_float8_float8() for reasoning.
3895 : */
3896 1680 : if (INTERVAL_IS_NOEND(offset) &&
3897 564 : (sub ? INTERVAL_IS_NOEND(base) : INTERVAL_IS_NOBEGIN(base)))
3898 228 : PG_RETURN_BOOL(true);
3899 :
3900 : /* We don't currently bother to avoid overflow hazards here */
3901 888 : if (sub)
3902 480 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
3903 : IntervalPGetDatum(base),
3904 : IntervalPGetDatum(offset)));
3905 : else
3906 408 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
3907 : IntervalPGetDatum(base),
3908 : IntervalPGetDatum(offset)));
3909 :
3910 888 : if (less)
3911 348 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3912 : else
3913 540 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3914 : }
3915 :
3916 :
3917 : /*
3918 : * Prepare state data for an interval aggregate function, that needs to compute
3919 : * sum and count, in the aggregate's memory context.
3920 : *
3921 : * The function is used when the state data needs to be allocated in aggregate's
3922 : * context. When the state data needs to be allocated in the current memory
3923 : * context, we use palloc0 directly e.g. interval_avg_deserialize().
3924 : */
3925 : static IntervalAggState *
3926 54 : makeIntervalAggState(FunctionCallInfo fcinfo)
3927 : {
3928 : IntervalAggState *state;
3929 : MemoryContext agg_context;
3930 : MemoryContext old_context;
3931 :
3932 54 : if (!AggCheckCallContext(fcinfo, &agg_context))
3933 0 : elog(ERROR, "aggregate function called in non-aggregate context");
3934 :
3935 54 : old_context = MemoryContextSwitchTo(agg_context);
3936 :
3937 54 : state = (IntervalAggState *) palloc0(sizeof(IntervalAggState));
3938 :
3939 54 : MemoryContextSwitchTo(old_context);
3940 :
3941 54 : return state;
3942 : }
3943 :
3944 : /*
3945 : * Accumulate a new input value for interval aggregate functions.
3946 : */
3947 : static void
3948 324 : do_interval_accum(IntervalAggState *state, Interval *newval)
3949 : {
3950 : /* Infinite inputs are counted separately, and do not affect "N" */
3951 324 : if (INTERVAL_IS_NOBEGIN(newval))
3952 : {
3953 60 : state->nInfcount++;
3954 60 : return;
3955 : }
3956 :
3957 264 : if (INTERVAL_IS_NOEND(newval))
3958 : {
3959 60 : state->pInfcount++;
3960 60 : return;
3961 : }
3962 :
3963 204 : finite_interval_pl(&state->sumX, newval, &state->sumX);
3964 204 : state->N++;
3965 : }
3966 :
3967 : /*
3968 : * Remove the given interval value from the aggregated state.
3969 : */
3970 : static void
3971 204 : do_interval_discard(IntervalAggState *state, Interval *newval)
3972 : {
3973 : /* Infinite inputs are counted separately, and do not affect "N" */
3974 204 : if (INTERVAL_IS_NOBEGIN(newval))
3975 : {
3976 24 : state->nInfcount--;
3977 24 : return;
3978 : }
3979 :
3980 180 : if (INTERVAL_IS_NOEND(newval))
3981 : {
3982 48 : state->pInfcount--;
3983 48 : return;
3984 : }
3985 :
3986 : /* Handle the to-be-discarded finite value. */
3987 132 : state->N--;
3988 132 : if (state->N > 0)
3989 48 : finite_interval_mi(&state->sumX, newval, &state->sumX);
3990 : else
3991 : {
3992 : /* All values discarded, reset the state */
3993 : Assert(state->N == 0);
3994 84 : memset(&state->sumX, 0, sizeof(state->sumX));
3995 : }
3996 : }
3997 :
3998 : /*
3999 : * Transition function for sum() and avg() interval aggregates.
4000 : */
4001 : Datum
4002 408 : interval_avg_accum(PG_FUNCTION_ARGS)
4003 : {
4004 : IntervalAggState *state;
4005 :
4006 408 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4007 :
4008 : /* Create the state data on the first call */
4009 408 : if (state == NULL)
4010 54 : state = makeIntervalAggState(fcinfo);
4011 :
4012 408 : if (!PG_ARGISNULL(1))
4013 324 : do_interval_accum(state, PG_GETARG_INTERVAL_P(1));
4014 :
4015 408 : PG_RETURN_POINTER(state);
4016 : }
4017 :
4018 : /*
4019 : * Combine function for sum() and avg() interval aggregates.
4020 : *
4021 : * Combine the given internal aggregate states and place the combination in
4022 : * the first argument.
4023 : */
4024 : Datum
4025 0 : interval_avg_combine(PG_FUNCTION_ARGS)
4026 : {
4027 : IntervalAggState *state1;
4028 : IntervalAggState *state2;
4029 :
4030 0 : state1 = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4031 0 : state2 = PG_ARGISNULL(1) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(1);
4032 :
4033 0 : if (state2 == NULL)
4034 0 : PG_RETURN_POINTER(state1);
4035 :
4036 0 : if (state1 == NULL)
4037 : {
4038 : /* manually copy all fields from state2 to state1 */
4039 0 : state1 = makeIntervalAggState(fcinfo);
4040 :
4041 0 : state1->N = state2->N;
4042 0 : state1->pInfcount = state2->pInfcount;
4043 0 : state1->nInfcount = state2->nInfcount;
4044 :
4045 0 : state1->sumX.day = state2->sumX.day;
4046 0 : state1->sumX.month = state2->sumX.month;
4047 0 : state1->sumX.time = state2->sumX.time;
4048 :
4049 0 : PG_RETURN_POINTER(state1);
4050 : }
4051 :
4052 0 : state1->N += state2->N;
4053 0 : state1->pInfcount += state2->pInfcount;
4054 0 : state1->nInfcount += state2->nInfcount;
4055 :
4056 : /* Accumulate finite interval values, if any. */
4057 0 : if (state2->N > 0)
4058 0 : finite_interval_pl(&state1->sumX, &state2->sumX, &state1->sumX);
4059 :
4060 0 : PG_RETURN_POINTER(state1);
4061 : }
4062 :
4063 : /*
4064 : * interval_avg_serialize
4065 : * Serialize IntervalAggState for interval aggregates.
4066 : */
4067 : Datum
4068 0 : interval_avg_serialize(PG_FUNCTION_ARGS)
4069 : {
4070 : IntervalAggState *state;
4071 : StringInfoData buf;
4072 : bytea *result;
4073 :
4074 : /* Ensure we disallow calling when not in aggregate context */
4075 0 : if (!AggCheckCallContext(fcinfo, NULL))
4076 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4077 :
4078 0 : state = (IntervalAggState *) PG_GETARG_POINTER(0);
4079 :
4080 0 : pq_begintypsend(&buf);
4081 :
4082 : /* N */
4083 0 : pq_sendint64(&buf, state->N);
4084 :
4085 : /* sumX */
4086 0 : pq_sendint64(&buf, state->sumX.time);
4087 0 : pq_sendint32(&buf, state->sumX.day);
4088 0 : pq_sendint32(&buf, state->sumX.month);
4089 :
4090 : /* pInfcount */
4091 0 : pq_sendint64(&buf, state->pInfcount);
4092 :
4093 : /* nInfcount */
4094 0 : pq_sendint64(&buf, state->nInfcount);
4095 :
4096 0 : result = pq_endtypsend(&buf);
4097 :
4098 0 : PG_RETURN_BYTEA_P(result);
4099 : }
4100 :
4101 : /*
4102 : * interval_avg_deserialize
4103 : * Deserialize bytea into IntervalAggState for interval aggregates.
4104 : */
4105 : Datum
4106 0 : interval_avg_deserialize(PG_FUNCTION_ARGS)
4107 : {
4108 : bytea *sstate;
4109 : IntervalAggState *result;
4110 : StringInfoData buf;
4111 :
4112 0 : if (!AggCheckCallContext(fcinfo, NULL))
4113 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4114 :
4115 0 : sstate = PG_GETARG_BYTEA_PP(0);
4116 :
4117 : /*
4118 : * Initialize a StringInfo so that we can "receive" it using the standard
4119 : * recv-function infrastructure.
4120 : */
4121 0 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
4122 0 : VARSIZE_ANY_EXHDR(sstate));
4123 :
4124 0 : result = (IntervalAggState *) palloc0(sizeof(IntervalAggState));
4125 :
4126 : /* N */
4127 0 : result->N = pq_getmsgint64(&buf);
4128 :
4129 : /* sumX */
4130 0 : result->sumX.time = pq_getmsgint64(&buf);
4131 0 : result->sumX.day = pq_getmsgint(&buf, 4);
4132 0 : result->sumX.month = pq_getmsgint(&buf, 4);
4133 :
4134 : /* pInfcount */
4135 0 : result->pInfcount = pq_getmsgint64(&buf);
4136 :
4137 : /* nInfcount */
4138 0 : result->nInfcount = pq_getmsgint64(&buf);
4139 :
4140 0 : pq_getmsgend(&buf);
4141 :
4142 0 : PG_RETURN_POINTER(result);
4143 : }
4144 :
4145 : /*
4146 : * Inverse transition function for sum() and avg() interval aggregates.
4147 : */
4148 : Datum
4149 264 : interval_avg_accum_inv(PG_FUNCTION_ARGS)
4150 : {
4151 : IntervalAggState *state;
4152 :
4153 264 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4154 :
4155 : /* Should not get here with no state */
4156 264 : if (state == NULL)
4157 0 : elog(ERROR, "interval_avg_accum_inv called with NULL state");
4158 :
4159 264 : if (!PG_ARGISNULL(1))
4160 204 : do_interval_discard(state, PG_GETARG_INTERVAL_P(1));
4161 :
4162 264 : PG_RETURN_POINTER(state);
4163 : }
4164 :
4165 : /* avg(interval) aggregate final function */
4166 : Datum
4167 168 : interval_avg(PG_FUNCTION_ARGS)
4168 : {
4169 : IntervalAggState *state;
4170 :
4171 168 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4172 :
4173 : /* If there were no non-null inputs, return NULL */
4174 168 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4175 18 : PG_RETURN_NULL();
4176 :
4177 : /*
4178 : * Aggregating infinities that all have the same sign produces infinity
4179 : * with that sign. Aggregating infinities with different signs results in
4180 : * an error.
4181 : */
4182 150 : if (state->pInfcount > 0 || state->nInfcount > 0)
4183 : {
4184 : Interval *result;
4185 :
4186 108 : if (state->pInfcount > 0 && state->nInfcount > 0)
4187 6 : ereport(ERROR,
4188 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4189 : errmsg("interval out of range.")));
4190 :
4191 102 : result = (Interval *) palloc(sizeof(Interval));
4192 102 : if (state->pInfcount > 0)
4193 60 : INTERVAL_NOEND(result);
4194 : else
4195 42 : INTERVAL_NOBEGIN(result);
4196 :
4197 102 : PG_RETURN_INTERVAL_P(result);
4198 : }
4199 :
4200 42 : return DirectFunctionCall2(interval_div,
4201 : IntervalPGetDatum(&state->sumX),
4202 : Float8GetDatum((double) state->N));
4203 : }
4204 :
4205 : /* sum(interval) aggregate final function */
4206 : Datum
4207 162 : interval_sum(PG_FUNCTION_ARGS)
4208 : {
4209 : IntervalAggState *state;
4210 : Interval *result;
4211 :
4212 162 : state = PG_ARGISNULL(0) ? NULL : (IntervalAggState *) PG_GETARG_POINTER(0);
4213 :
4214 : /* If there were no non-null inputs, return NULL */
4215 162 : if (state == NULL || IA_TOTAL_COUNT(state) == 0)
4216 18 : PG_RETURN_NULL();
4217 :
4218 : /*
4219 : * Aggregating infinities that all have the same sign produces infinity
4220 : * with that sign. Aggregating infinities with different signs results in
4221 : * an error.
4222 : */
4223 144 : if (state->pInfcount > 0 && state->nInfcount > 0)
4224 6 : ereport(ERROR,
4225 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4226 : errmsg("interval out of range.")));
4227 :
4228 138 : result = (Interval *) palloc(sizeof(Interval));
4229 :
4230 138 : if (state->pInfcount > 0)
4231 60 : INTERVAL_NOEND(result);
4232 78 : else if (state->nInfcount > 0)
4233 42 : INTERVAL_NOBEGIN(result);
4234 : else
4235 36 : memcpy(result, &state->sumX, sizeof(Interval));
4236 :
4237 138 : PG_RETURN_INTERVAL_P(result);
4238 : }
4239 :
4240 : /* timestamp_age()
4241 : * Calculate time difference while retaining year/month fields.
4242 : * Note that this does not result in an accurate absolute time span
4243 : * since year and month are out of context once the arithmetic
4244 : * is done.
4245 : */
4246 : Datum
4247 36 : timestamp_age(PG_FUNCTION_ARGS)
4248 : {
4249 36 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
4250 36 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
4251 : Interval *result;
4252 : fsec_t fsec1,
4253 : fsec2;
4254 : struct pg_itm tt,
4255 36 : *tm = &tt;
4256 : struct pg_tm tt1,
4257 36 : *tm1 = &tt1;
4258 : struct pg_tm tt2,
4259 36 : *tm2 = &tt2;
4260 :
4261 36 : result = (Interval *) palloc(sizeof(Interval));
4262 :
4263 : /*
4264 : * Handle infinities.
4265 : *
4266 : * We treat anything that amounts to "infinity - infinity" as an error,
4267 : * since the interval type has nothing equivalent to NaN.
4268 : */
4269 36 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4270 : {
4271 12 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4272 6 : ereport(ERROR,
4273 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4274 : errmsg("interval out of range")));
4275 : else
4276 6 : INTERVAL_NOBEGIN(result);
4277 : }
4278 24 : else if (TIMESTAMP_IS_NOEND(dt1))
4279 : {
4280 12 : if (TIMESTAMP_IS_NOEND(dt2))
4281 6 : ereport(ERROR,
4282 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4283 : errmsg("interval out of range")));
4284 : else
4285 6 : INTERVAL_NOEND(result);
4286 : }
4287 12 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4288 6 : INTERVAL_NOEND(result);
4289 6 : else if (TIMESTAMP_IS_NOEND(dt2))
4290 6 : INTERVAL_NOBEGIN(result);
4291 0 : else if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
4292 0 : timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
4293 : {
4294 : /* form the symbolic difference */
4295 0 : tm->tm_usec = fsec1 - fsec2;
4296 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4297 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4298 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4299 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4300 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4301 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4302 :
4303 : /* flip sign if necessary... */
4304 0 : if (dt1 < dt2)
4305 : {
4306 0 : tm->tm_usec = -tm->tm_usec;
4307 0 : tm->tm_sec = -tm->tm_sec;
4308 0 : tm->tm_min = -tm->tm_min;
4309 0 : tm->tm_hour = -tm->tm_hour;
4310 0 : tm->tm_mday = -tm->tm_mday;
4311 0 : tm->tm_mon = -tm->tm_mon;
4312 0 : tm->tm_year = -tm->tm_year;
4313 : }
4314 :
4315 : /* propagate any negative fields into the next higher field */
4316 0 : while (tm->tm_usec < 0)
4317 : {
4318 0 : tm->tm_usec += USECS_PER_SEC;
4319 0 : tm->tm_sec--;
4320 : }
4321 :
4322 0 : while (tm->tm_sec < 0)
4323 : {
4324 0 : tm->tm_sec += SECS_PER_MINUTE;
4325 0 : tm->tm_min--;
4326 : }
4327 :
4328 0 : while (tm->tm_min < 0)
4329 : {
4330 0 : tm->tm_min += MINS_PER_HOUR;
4331 0 : tm->tm_hour--;
4332 : }
4333 :
4334 0 : while (tm->tm_hour < 0)
4335 : {
4336 0 : tm->tm_hour += HOURS_PER_DAY;
4337 0 : tm->tm_mday--;
4338 : }
4339 :
4340 0 : while (tm->tm_mday < 0)
4341 : {
4342 0 : if (dt1 < dt2)
4343 : {
4344 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4345 0 : tm->tm_mon--;
4346 : }
4347 : else
4348 : {
4349 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4350 0 : tm->tm_mon--;
4351 : }
4352 : }
4353 :
4354 0 : while (tm->tm_mon < 0)
4355 : {
4356 0 : tm->tm_mon += MONTHS_PER_YEAR;
4357 0 : tm->tm_year--;
4358 : }
4359 :
4360 : /* recover sign if necessary... */
4361 0 : if (dt1 < dt2)
4362 : {
4363 0 : tm->tm_usec = -tm->tm_usec;
4364 0 : tm->tm_sec = -tm->tm_sec;
4365 0 : tm->tm_min = -tm->tm_min;
4366 0 : tm->tm_hour = -tm->tm_hour;
4367 0 : tm->tm_mday = -tm->tm_mday;
4368 0 : tm->tm_mon = -tm->tm_mon;
4369 0 : tm->tm_year = -tm->tm_year;
4370 : }
4371 :
4372 0 : if (itm2interval(tm, result) != 0)
4373 0 : ereport(ERROR,
4374 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4375 : errmsg("interval out of range")));
4376 : }
4377 : else
4378 0 : ereport(ERROR,
4379 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4380 : errmsg("timestamp out of range")));
4381 :
4382 24 : PG_RETURN_INTERVAL_P(result);
4383 : }
4384 :
4385 :
4386 : /* timestamptz_age()
4387 : * Calculate time difference while retaining year/month fields.
4388 : * Note that this does not result in an accurate absolute time span
4389 : * since year and month are out of context once the arithmetic
4390 : * is done.
4391 : */
4392 : Datum
4393 36 : timestamptz_age(PG_FUNCTION_ARGS)
4394 : {
4395 36 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
4396 36 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
4397 : Interval *result;
4398 : fsec_t fsec1,
4399 : fsec2;
4400 : struct pg_itm tt,
4401 36 : *tm = &tt;
4402 : struct pg_tm tt1,
4403 36 : *tm1 = &tt1;
4404 : struct pg_tm tt2,
4405 36 : *tm2 = &tt2;
4406 : int tz1;
4407 : int tz2;
4408 :
4409 36 : result = (Interval *) palloc(sizeof(Interval));
4410 :
4411 : /*
4412 : * Handle infinities.
4413 : *
4414 : * We treat anything that amounts to "infinity - infinity" as an error,
4415 : * since the interval type has nothing equivalent to NaN.
4416 : */
4417 36 : if (TIMESTAMP_IS_NOBEGIN(dt1))
4418 : {
4419 12 : if (TIMESTAMP_IS_NOBEGIN(dt2))
4420 6 : ereport(ERROR,
4421 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4422 : errmsg("interval out of range")));
4423 : else
4424 6 : INTERVAL_NOBEGIN(result);
4425 : }
4426 24 : else if (TIMESTAMP_IS_NOEND(dt1))
4427 : {
4428 12 : if (TIMESTAMP_IS_NOEND(dt2))
4429 6 : ereport(ERROR,
4430 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4431 : errmsg("interval out of range")));
4432 : else
4433 6 : INTERVAL_NOEND(result);
4434 : }
4435 12 : else if (TIMESTAMP_IS_NOBEGIN(dt2))
4436 6 : INTERVAL_NOEND(result);
4437 6 : else if (TIMESTAMP_IS_NOEND(dt2))
4438 6 : INTERVAL_NOBEGIN(result);
4439 0 : else if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
4440 0 : timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
4441 : {
4442 : /* form the symbolic difference */
4443 0 : tm->tm_usec = fsec1 - fsec2;
4444 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
4445 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
4446 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
4447 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
4448 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
4449 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
4450 :
4451 : /* flip sign if necessary... */
4452 0 : if (dt1 < dt2)
4453 : {
4454 0 : tm->tm_usec = -tm->tm_usec;
4455 0 : tm->tm_sec = -tm->tm_sec;
4456 0 : tm->tm_min = -tm->tm_min;
4457 0 : tm->tm_hour = -tm->tm_hour;
4458 0 : tm->tm_mday = -tm->tm_mday;
4459 0 : tm->tm_mon = -tm->tm_mon;
4460 0 : tm->tm_year = -tm->tm_year;
4461 : }
4462 :
4463 : /* propagate any negative fields into the next higher field */
4464 0 : while (tm->tm_usec < 0)
4465 : {
4466 0 : tm->tm_usec += USECS_PER_SEC;
4467 0 : tm->tm_sec--;
4468 : }
4469 :
4470 0 : while (tm->tm_sec < 0)
4471 : {
4472 0 : tm->tm_sec += SECS_PER_MINUTE;
4473 0 : tm->tm_min--;
4474 : }
4475 :
4476 0 : while (tm->tm_min < 0)
4477 : {
4478 0 : tm->tm_min += MINS_PER_HOUR;
4479 0 : tm->tm_hour--;
4480 : }
4481 :
4482 0 : while (tm->tm_hour < 0)
4483 : {
4484 0 : tm->tm_hour += HOURS_PER_DAY;
4485 0 : tm->tm_mday--;
4486 : }
4487 :
4488 0 : while (tm->tm_mday < 0)
4489 : {
4490 0 : if (dt1 < dt2)
4491 : {
4492 0 : tm->tm_mday += day_tab[isleap(tm1->tm_year)][tm1->tm_mon - 1];
4493 0 : tm->tm_mon--;
4494 : }
4495 : else
4496 : {
4497 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
4498 0 : tm->tm_mon--;
4499 : }
4500 : }
4501 :
4502 0 : while (tm->tm_mon < 0)
4503 : {
4504 0 : tm->tm_mon += MONTHS_PER_YEAR;
4505 0 : tm->tm_year--;
4506 : }
4507 :
4508 : /*
4509 : * Note: we deliberately ignore any difference between tz1 and tz2.
4510 : */
4511 :
4512 : /* recover sign if necessary... */
4513 0 : if (dt1 < dt2)
4514 : {
4515 0 : tm->tm_usec = -tm->tm_usec;
4516 0 : tm->tm_sec = -tm->tm_sec;
4517 0 : tm->tm_min = -tm->tm_min;
4518 0 : tm->tm_hour = -tm->tm_hour;
4519 0 : tm->tm_mday = -tm->tm_mday;
4520 0 : tm->tm_mon = -tm->tm_mon;
4521 0 : tm->tm_year = -tm->tm_year;
4522 : }
4523 :
4524 0 : if (itm2interval(tm, result) != 0)
4525 0 : ereport(ERROR,
4526 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4527 : errmsg("interval out of range")));
4528 : }
4529 : else
4530 0 : ereport(ERROR,
4531 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4532 : errmsg("timestamp out of range")));
4533 :
4534 24 : PG_RETURN_INTERVAL_P(result);
4535 : }
4536 :
4537 :
4538 : /*----------------------------------------------------------
4539 : * Conversion operators.
4540 : *---------------------------------------------------------*/
4541 :
4542 :
4543 : /* timestamp_bin()
4544 : * Bin timestamp into specified interval.
4545 : */
4546 : Datum
4547 276 : timestamp_bin(PG_FUNCTION_ARGS)
4548 : {
4549 276 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4550 276 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4551 276 : Timestamp origin = PG_GETARG_TIMESTAMP(2);
4552 : Timestamp result,
4553 : stride_usecs,
4554 : tm_diff,
4555 : tm_modulo,
4556 : tm_delta;
4557 :
4558 276 : if (TIMESTAMP_NOT_FINITE(timestamp))
4559 0 : PG_RETURN_TIMESTAMP(timestamp);
4560 :
4561 276 : if (TIMESTAMP_NOT_FINITE(origin))
4562 0 : ereport(ERROR,
4563 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4564 : errmsg("origin out of range")));
4565 :
4566 276 : if (INTERVAL_NOT_FINITE(stride))
4567 12 : ereport(ERROR,
4568 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4569 : errmsg("timestamps cannot be binned into infinite intervals")));
4570 :
4571 264 : if (stride->month != 0)
4572 12 : ereport(ERROR,
4573 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4574 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4575 :
4576 252 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4577 246 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4578 6 : ereport(ERROR,
4579 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4580 : errmsg("interval out of range")));
4581 :
4582 246 : if (stride_usecs <= 0)
4583 12 : ereport(ERROR,
4584 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4585 : errmsg("stride must be greater than zero")));
4586 :
4587 234 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4588 6 : ereport(ERROR,
4589 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4590 : errmsg("interval out of range")));
4591 :
4592 : /* These calculations cannot overflow */
4593 228 : tm_modulo = tm_diff % stride_usecs;
4594 228 : tm_delta = tm_diff - tm_modulo;
4595 228 : result = origin + tm_delta;
4596 :
4597 : /*
4598 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4599 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4600 : * since the result might now be out of the range origin .. timestamp.
4601 : */
4602 228 : if (tm_modulo < 0)
4603 : {
4604 78 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4605 78 : !IS_VALID_TIMESTAMP(result))
4606 6 : ereport(ERROR,
4607 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4608 : errmsg("timestamp out of range")));
4609 : }
4610 :
4611 222 : PG_RETURN_TIMESTAMP(result);
4612 : }
4613 :
4614 : /* timestamp_trunc()
4615 : * Truncate timestamp to specified units.
4616 : */
4617 : Datum
4618 1386 : timestamp_trunc(PG_FUNCTION_ARGS)
4619 : {
4620 1386 : text *units = PG_GETARG_TEXT_PP(0);
4621 1386 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4622 : Timestamp result;
4623 : int type,
4624 : val;
4625 : char *lowunits;
4626 : fsec_t fsec;
4627 : struct pg_tm tt,
4628 1386 : *tm = &tt;
4629 :
4630 1386 : if (TIMESTAMP_NOT_FINITE(timestamp))
4631 0 : PG_RETURN_TIMESTAMP(timestamp);
4632 :
4633 1386 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4634 1386 : VARSIZE_ANY_EXHDR(units),
4635 : false);
4636 :
4637 1386 : type = DecodeUnits(0, lowunits, &val);
4638 :
4639 1386 : if (type == UNITS)
4640 : {
4641 1386 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
4642 0 : ereport(ERROR,
4643 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4644 : errmsg("timestamp out of range")));
4645 :
4646 1386 : switch (val)
4647 : {
4648 30 : case DTK_WEEK:
4649 : {
4650 : int woy;
4651 :
4652 30 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4653 :
4654 : /*
4655 : * If it is week 52/53 and the month is January, then the
4656 : * week must belong to the previous year. Also, some
4657 : * December dates belong to the next year.
4658 : */
4659 30 : if (woy >= 52 && tm->tm_mon == 1)
4660 0 : --tm->tm_year;
4661 30 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4662 0 : ++tm->tm_year;
4663 30 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4664 30 : tm->tm_hour = 0;
4665 30 : tm->tm_min = 0;
4666 30 : tm->tm_sec = 0;
4667 30 : fsec = 0;
4668 30 : break;
4669 : }
4670 6 : case DTK_MILLENNIUM:
4671 : /* see comments in timestamptz_trunc */
4672 6 : if (tm->tm_year > 0)
4673 6 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4674 : else
4675 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4676 : /* FALL THRU */
4677 : case DTK_CENTURY:
4678 : /* see comments in timestamptz_trunc */
4679 12 : if (tm->tm_year > 0)
4680 12 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4681 : else
4682 0 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4683 : /* FALL THRU */
4684 : case DTK_DECADE:
4685 : /* see comments in timestamptz_trunc */
4686 12 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4687 : {
4688 0 : if (tm->tm_year > 0)
4689 0 : tm->tm_year = (tm->tm_year / 10) * 10;
4690 : else
4691 0 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4692 : }
4693 : /* FALL THRU */
4694 : case DTK_YEAR:
4695 12 : tm->tm_mon = 1;
4696 : /* FALL THRU */
4697 12 : case DTK_QUARTER:
4698 12 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4699 : /* FALL THRU */
4700 12 : case DTK_MONTH:
4701 12 : tm->tm_mday = 1;
4702 : /* FALL THRU */
4703 1236 : case DTK_DAY:
4704 1236 : tm->tm_hour = 0;
4705 : /* FALL THRU */
4706 1260 : case DTK_HOUR:
4707 1260 : tm->tm_min = 0;
4708 : /* FALL THRU */
4709 1284 : case DTK_MINUTE:
4710 1284 : tm->tm_sec = 0;
4711 : /* FALL THRU */
4712 1308 : case DTK_SECOND:
4713 1308 : fsec = 0;
4714 1308 : break;
4715 :
4716 24 : case DTK_MILLISEC:
4717 24 : fsec = (fsec / 1000) * 1000;
4718 24 : break;
4719 :
4720 24 : case DTK_MICROSEC:
4721 24 : break;
4722 :
4723 0 : default:
4724 0 : ereport(ERROR,
4725 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4726 : errmsg("unit \"%s\" not supported for type %s",
4727 : lowunits, format_type_be(TIMESTAMPOID))));
4728 : result = 0;
4729 : }
4730 :
4731 1386 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
4732 0 : ereport(ERROR,
4733 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4734 : errmsg("timestamp out of range")));
4735 : }
4736 : else
4737 : {
4738 0 : ereport(ERROR,
4739 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4740 : errmsg("unit \"%s\" not recognized for type %s",
4741 : lowunits, format_type_be(TIMESTAMPOID))));
4742 : result = 0;
4743 : }
4744 :
4745 1386 : PG_RETURN_TIMESTAMP(result);
4746 : }
4747 :
4748 : /* timestamptz_bin()
4749 : * Bin timestamptz into specified interval using specified origin.
4750 : */
4751 : Datum
4752 132 : timestamptz_bin(PG_FUNCTION_ARGS)
4753 : {
4754 132 : Interval *stride = PG_GETARG_INTERVAL_P(0);
4755 132 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
4756 132 : TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
4757 : TimestampTz result,
4758 : stride_usecs,
4759 : tm_diff,
4760 : tm_modulo,
4761 : tm_delta;
4762 :
4763 132 : if (TIMESTAMP_NOT_FINITE(timestamp))
4764 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
4765 :
4766 132 : if (TIMESTAMP_NOT_FINITE(origin))
4767 0 : ereport(ERROR,
4768 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4769 : errmsg("origin out of range")));
4770 :
4771 132 : if (INTERVAL_NOT_FINITE(stride))
4772 0 : ereport(ERROR,
4773 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4774 : errmsg("timestamps cannot be binned into infinite intervals")));
4775 :
4776 132 : if (stride->month != 0)
4777 12 : ereport(ERROR,
4778 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4779 : errmsg("timestamps cannot be binned into intervals containing months or years")));
4780 :
4781 120 : if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
4782 114 : unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
4783 6 : ereport(ERROR,
4784 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4785 : errmsg("interval out of range")));
4786 :
4787 114 : if (stride_usecs <= 0)
4788 12 : ereport(ERROR,
4789 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4790 : errmsg("stride must be greater than zero")));
4791 :
4792 102 : if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
4793 6 : ereport(ERROR,
4794 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4795 : errmsg("interval out of range")));
4796 :
4797 : /* These calculations cannot overflow */
4798 96 : tm_modulo = tm_diff % stride_usecs;
4799 96 : tm_delta = tm_diff - tm_modulo;
4800 96 : result = origin + tm_delta;
4801 :
4802 : /*
4803 : * We want to round towards -infinity, not 0, when tm_diff is negative and
4804 : * not a multiple of stride_usecs. This adjustment *can* cause overflow,
4805 : * since the result might now be out of the range origin .. timestamp.
4806 : */
4807 96 : if (tm_modulo < 0)
4808 : {
4809 6 : if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
4810 6 : !IS_VALID_TIMESTAMP(result))
4811 6 : ereport(ERROR,
4812 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4813 : errmsg("timestamp out of range")));
4814 : }
4815 :
4816 90 : PG_RETURN_TIMESTAMPTZ(result);
4817 : }
4818 :
4819 : /*
4820 : * Common code for timestamptz_trunc() and timestamptz_trunc_zone().
4821 : *
4822 : * tzp identifies the zone to truncate with respect to. We assume
4823 : * infinite timestamps have already been rejected.
4824 : */
4825 : static TimestampTz
4826 1308 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
4827 : {
4828 : TimestampTz result;
4829 : int tz;
4830 : int type,
4831 : val;
4832 1308 : bool redotz = false;
4833 : char *lowunits;
4834 : fsec_t fsec;
4835 : struct pg_tm tt,
4836 1308 : *tm = &tt;
4837 :
4838 1308 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4839 1308 : VARSIZE_ANY_EXHDR(units),
4840 : false);
4841 :
4842 1308 : type = DecodeUnits(0, lowunits, &val);
4843 :
4844 1308 : if (type == UNITS)
4845 : {
4846 1308 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
4847 0 : ereport(ERROR,
4848 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4849 : errmsg("timestamp out of range")));
4850 :
4851 1308 : switch (val)
4852 : {
4853 6 : case DTK_WEEK:
4854 : {
4855 : int woy;
4856 :
4857 6 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
4858 :
4859 : /*
4860 : * If it is week 52/53 and the month is January, then the
4861 : * week must belong to the previous year. Also, some
4862 : * December dates belong to the next year.
4863 : */
4864 6 : if (woy >= 52 && tm->tm_mon == 1)
4865 0 : --tm->tm_year;
4866 6 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
4867 0 : ++tm->tm_year;
4868 6 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4869 6 : tm->tm_hour = 0;
4870 6 : tm->tm_min = 0;
4871 6 : tm->tm_sec = 0;
4872 6 : fsec = 0;
4873 6 : redotz = true;
4874 6 : break;
4875 : }
4876 : /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
4877 6 : case DTK_MILLENNIUM:
4878 :
4879 : /*
4880 : * truncating to the millennium? what is this supposed to
4881 : * mean? let us put the first year of the millennium... i.e.
4882 : * -1000, 1, 1001, 2001...
4883 : */
4884 6 : if (tm->tm_year > 0)
4885 6 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4886 : else
4887 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4888 : /* FALL THRU */
4889 : case DTK_CENTURY:
4890 : /* truncating to the century? as above: -100, 1, 101... */
4891 30 : if (tm->tm_year > 0)
4892 24 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4893 : else
4894 6 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4895 : /* FALL THRU */
4896 : case DTK_DECADE:
4897 :
4898 : /*
4899 : * truncating to the decade? first year of the decade. must
4900 : * not be applied if year was truncated before!
4901 : */
4902 48 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4903 : {
4904 18 : if (tm->tm_year > 0)
4905 12 : tm->tm_year = (tm->tm_year / 10) * 10;
4906 : else
4907 6 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4908 : }
4909 : /* FALL THRU */
4910 : case DTK_YEAR:
4911 48 : tm->tm_mon = 1;
4912 : /* FALL THRU */
4913 48 : case DTK_QUARTER:
4914 48 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4915 : /* FALL THRU */
4916 48 : case DTK_MONTH:
4917 48 : tm->tm_mday = 1;
4918 : /* FALL THRU */
4919 1272 : case DTK_DAY:
4920 1272 : tm->tm_hour = 0;
4921 1272 : redotz = true; /* for all cases >= DAY */
4922 : /* FALL THRU */
4923 1278 : case DTK_HOUR:
4924 1278 : tm->tm_min = 0;
4925 : /* FALL THRU */
4926 1284 : case DTK_MINUTE:
4927 1284 : tm->tm_sec = 0;
4928 : /* FALL THRU */
4929 1290 : case DTK_SECOND:
4930 1290 : fsec = 0;
4931 1290 : break;
4932 6 : case DTK_MILLISEC:
4933 6 : fsec = (fsec / 1000) * 1000;
4934 6 : break;
4935 6 : case DTK_MICROSEC:
4936 6 : break;
4937 :
4938 0 : default:
4939 0 : ereport(ERROR,
4940 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4941 : errmsg("unit \"%s\" not supported for type %s",
4942 : lowunits, format_type_be(TIMESTAMPTZOID))));
4943 : result = 0;
4944 : }
4945 :
4946 1308 : if (redotz)
4947 1278 : tz = DetermineTimeZoneOffset(tm, tzp);
4948 :
4949 1308 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
4950 0 : ereport(ERROR,
4951 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4952 : errmsg("timestamp out of range")));
4953 : }
4954 : else
4955 : {
4956 0 : ereport(ERROR,
4957 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4958 : errmsg("unit \"%s\" not recognized for type %s",
4959 : lowunits, format_type_be(TIMESTAMPTZOID))));
4960 : result = 0;
4961 : }
4962 :
4963 1308 : return result;
4964 : }
4965 :
4966 : /* timestamptz_trunc()
4967 : * Truncate timestamptz to specified units in session timezone.
4968 : */
4969 : Datum
4970 1254 : timestamptz_trunc(PG_FUNCTION_ARGS)
4971 : {
4972 1254 : text *units = PG_GETARG_TEXT_PP(0);
4973 1254 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
4974 : TimestampTz result;
4975 :
4976 1254 : if (TIMESTAMP_NOT_FINITE(timestamp))
4977 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
4978 :
4979 1254 : result = timestamptz_trunc_internal(units, timestamp, session_timezone);
4980 :
4981 1254 : PG_RETURN_TIMESTAMPTZ(result);
4982 : }
4983 :
4984 : /* timestamptz_trunc_zone()
4985 : * Truncate timestamptz to specified units in specified timezone.
4986 : */
4987 : Datum
4988 54 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
4989 : {
4990 54 : text *units = PG_GETARG_TEXT_PP(0);
4991 54 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
4992 54 : text *zone = PG_GETARG_TEXT_PP(2);
4993 : TimestampTz result;
4994 : pg_tz *tzp;
4995 :
4996 : /*
4997 : * timestamptz_zone() doesn't look up the zone for infinite inputs, so we
4998 : * don't do so here either.
4999 : */
5000 54 : if (TIMESTAMP_NOT_FINITE(timestamp))
5001 0 : PG_RETURN_TIMESTAMP(timestamp);
5002 :
5003 : /*
5004 : * Look up the requested timezone.
5005 : */
5006 54 : tzp = lookup_timezone(zone);
5007 :
5008 54 : result = timestamptz_trunc_internal(units, timestamp, tzp);
5009 :
5010 54 : PG_RETURN_TIMESTAMPTZ(result);
5011 : }
5012 :
5013 : /* interval_trunc()
5014 : * Extract specified field from interval.
5015 : */
5016 : Datum
5017 12 : interval_trunc(PG_FUNCTION_ARGS)
5018 : {
5019 12 : text *units = PG_GETARG_TEXT_PP(0);
5020 12 : Interval *interval = PG_GETARG_INTERVAL_P(1);
5021 : Interval *result;
5022 : int type,
5023 : val;
5024 : char *lowunits;
5025 : struct pg_itm tt,
5026 12 : *tm = &tt;
5027 :
5028 12 : result = (Interval *) palloc(sizeof(Interval));
5029 :
5030 12 : if (INTERVAL_NOT_FINITE(interval))
5031 : {
5032 12 : memcpy(result, interval, sizeof(Interval));
5033 12 : PG_RETURN_INTERVAL_P(result);
5034 : }
5035 :
5036 0 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5037 0 : VARSIZE_ANY_EXHDR(units),
5038 : false);
5039 :
5040 0 : type = DecodeUnits(0, lowunits, &val);
5041 :
5042 0 : if (type == UNITS)
5043 : {
5044 0 : interval2itm(*interval, tm);
5045 0 : switch (val)
5046 : {
5047 0 : case DTK_MILLENNIUM:
5048 : /* caution: C division may have negative remainder */
5049 0 : tm->tm_year = (tm->tm_year / 1000) * 1000;
5050 : /* FALL THRU */
5051 0 : case DTK_CENTURY:
5052 : /* caution: C division may have negative remainder */
5053 0 : tm->tm_year = (tm->tm_year / 100) * 100;
5054 : /* FALL THRU */
5055 0 : case DTK_DECADE:
5056 : /* caution: C division may have negative remainder */
5057 0 : tm->tm_year = (tm->tm_year / 10) * 10;
5058 : /* FALL THRU */
5059 0 : case DTK_YEAR:
5060 0 : tm->tm_mon = 0;
5061 : /* FALL THRU */
5062 0 : case DTK_QUARTER:
5063 0 : tm->tm_mon = 3 * (tm->tm_mon / 3);
5064 : /* FALL THRU */
5065 0 : case DTK_MONTH:
5066 0 : tm->tm_mday = 0;
5067 : /* FALL THRU */
5068 0 : case DTK_DAY:
5069 0 : tm->tm_hour = 0;
5070 : /* FALL THRU */
5071 0 : case DTK_HOUR:
5072 0 : tm->tm_min = 0;
5073 : /* FALL THRU */
5074 0 : case DTK_MINUTE:
5075 0 : tm->tm_sec = 0;
5076 : /* FALL THRU */
5077 0 : case DTK_SECOND:
5078 0 : tm->tm_usec = 0;
5079 0 : break;
5080 0 : case DTK_MILLISEC:
5081 0 : tm->tm_usec = (tm->tm_usec / 1000) * 1000;
5082 0 : break;
5083 0 : case DTK_MICROSEC:
5084 0 : break;
5085 :
5086 0 : default:
5087 0 : ereport(ERROR,
5088 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5089 : errmsg("unit \"%s\" not supported for type %s",
5090 : lowunits, format_type_be(INTERVALOID)),
5091 : (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
5092 : }
5093 :
5094 0 : if (itm2interval(tm, result) != 0)
5095 0 : ereport(ERROR,
5096 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5097 : errmsg("interval out of range")));
5098 : }
5099 : else
5100 : {
5101 0 : ereport(ERROR,
5102 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5103 : errmsg("unit \"%s\" not recognized for type %s",
5104 : lowunits, format_type_be(INTERVALOID))));
5105 : }
5106 :
5107 0 : PG_RETURN_INTERVAL_P(result);
5108 : }
5109 :
5110 : /* isoweek2j()
5111 : *
5112 : * Return the Julian day which corresponds to the first day (Monday) of the given ISO 8601 year and week.
5113 : * Julian days are used to convert between ISO week dates and Gregorian dates.
5114 : */
5115 : int
5116 1590 : isoweek2j(int year, int week)
5117 : {
5118 : int day0,
5119 : day4;
5120 :
5121 : /* fourth day of current year */
5122 1590 : day4 = date2j(year, 1, 4);
5123 :
5124 : /* day0 == offset to first day of week (Monday) */
5125 1590 : day0 = j2day(day4 - 1);
5126 :
5127 1590 : return ((week - 1) * 7) + (day4 - day0);
5128 : }
5129 :
5130 : /* isoweek2date()
5131 : * Convert ISO week of year number to date.
5132 : * The year field must be specified with the ISO year!
5133 : * karel 2000/08/07
5134 : */
5135 : void
5136 36 : isoweek2date(int woy, int *year, int *mon, int *mday)
5137 : {
5138 36 : j2date(isoweek2j(*year, woy), year, mon, mday);
5139 36 : }
5140 :
5141 : /* isoweekdate2date()
5142 : *
5143 : * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
5144 : * Gregorian day of week sent so weekday strings can be supplied.
5145 : * Populates year, mon, and mday with the correct Gregorian values.
5146 : * year must be passed in as the ISO year.
5147 : */
5148 : void
5149 24 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
5150 : {
5151 : int jday;
5152 :
5153 24 : jday = isoweek2j(*year, isoweek);
5154 : /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
5155 24 : if (wday > 1)
5156 0 : jday += wday - 2;
5157 : else
5158 24 : jday += 6;
5159 24 : j2date(jday, year, mon, mday);
5160 24 : }
5161 :
5162 : /* date2isoweek()
5163 : *
5164 : * Returns ISO week number of year.
5165 : */
5166 : int
5167 2424 : date2isoweek(int year, int mon, int mday)
5168 : {
5169 : float8 result;
5170 : int day0,
5171 : day4,
5172 : dayn;
5173 :
5174 : /* current day */
5175 2424 : dayn = date2j(year, mon, mday);
5176 :
5177 : /* fourth day of current year */
5178 2424 : day4 = date2j(year, 1, 4);
5179 :
5180 : /* day0 == offset to first day of week (Monday) */
5181 2424 : day0 = j2day(day4 - 1);
5182 :
5183 : /*
5184 : * We need the first week containing a Thursday, otherwise this day falls
5185 : * into the previous year for purposes of counting weeks
5186 : */
5187 2424 : if (dayn < day4 - day0)
5188 : {
5189 36 : day4 = date2j(year - 1, 1, 4);
5190 :
5191 : /* day0 == offset to first day of week (Monday) */
5192 36 : day0 = j2day(day4 - 1);
5193 : }
5194 :
5195 2424 : result = (dayn - (day4 - day0)) / 7 + 1;
5196 :
5197 : /*
5198 : * Sometimes the last few days in a year will fall into the first week of
5199 : * the next year, so check for this.
5200 : */
5201 2424 : if (result >= 52)
5202 : {
5203 270 : day4 = date2j(year + 1, 1, 4);
5204 :
5205 : /* day0 == offset to first day of week (Monday) */
5206 270 : day0 = j2day(day4 - 1);
5207 :
5208 270 : if (dayn >= day4 - day0)
5209 162 : result = (dayn - (day4 - day0)) / 7 + 1;
5210 : }
5211 :
5212 2424 : return (int) result;
5213 : }
5214 :
5215 :
5216 : /* date2isoyear()
5217 : *
5218 : * Returns ISO 8601 year number.
5219 : * Note: zero or negative results follow the year-zero-exists convention.
5220 : */
5221 : int
5222 14586 : date2isoyear(int year, int mon, int mday)
5223 : {
5224 : float8 result;
5225 : int day0,
5226 : day4,
5227 : dayn;
5228 :
5229 : /* current day */
5230 14586 : dayn = date2j(year, mon, mday);
5231 :
5232 : /* fourth day of current year */
5233 14586 : day4 = date2j(year, 1, 4);
5234 :
5235 : /* day0 == offset to first day of week (Monday) */
5236 14586 : day0 = j2day(day4 - 1);
5237 :
5238 : /*
5239 : * We need the first week containing a Thursday, otherwise this day falls
5240 : * into the previous year for purposes of counting weeks
5241 : */
5242 14586 : if (dayn < day4 - day0)
5243 : {
5244 228 : day4 = date2j(year - 1, 1, 4);
5245 :
5246 : /* day0 == offset to first day of week (Monday) */
5247 228 : day0 = j2day(day4 - 1);
5248 :
5249 228 : year--;
5250 : }
5251 :
5252 14586 : result = (dayn - (day4 - day0)) / 7 + 1;
5253 :
5254 : /*
5255 : * Sometimes the last few days in a year will fall into the first week of
5256 : * the next year, so check for this.
5257 : */
5258 14586 : if (result >= 52)
5259 : {
5260 1710 : day4 = date2j(year + 1, 1, 4);
5261 :
5262 : /* day0 == offset to first day of week (Monday) */
5263 1710 : day0 = j2day(day4 - 1);
5264 :
5265 1710 : if (dayn >= day4 - day0)
5266 1026 : year++;
5267 : }
5268 :
5269 14586 : return year;
5270 : }
5271 :
5272 :
5273 : /* date2isoyearday()
5274 : *
5275 : * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
5276 : * Possible return values are 1 through 371 (364 in non-leap years).
5277 : */
5278 : int
5279 1524 : date2isoyearday(int year, int mon, int mday)
5280 : {
5281 1524 : return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
5282 : }
5283 :
5284 : /*
5285 : * NonFiniteTimestampTzPart
5286 : *
5287 : * Used by timestamp_part and timestamptz_part when extracting from infinite
5288 : * timestamp[tz]. Returns +/-Infinity if that is the appropriate result,
5289 : * otherwise returns zero (which should be taken as meaning to return NULL).
5290 : *
5291 : * Errors thrown here for invalid units should exactly match those that
5292 : * would be thrown in the calling functions, else there will be unexpected
5293 : * discrepancies between finite- and infinite-input cases.
5294 : */
5295 : static float8
5296 612 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
5297 : bool isNegative, bool isTz)
5298 : {
5299 612 : if ((type != UNITS) && (type != RESERV))
5300 0 : ereport(ERROR,
5301 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5302 : errmsg("unit \"%s\" not recognized for type %s",
5303 : lowunits,
5304 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5305 :
5306 612 : switch (unit)
5307 : {
5308 : /* Oscillating units */
5309 396 : case DTK_MICROSEC:
5310 : case DTK_MILLISEC:
5311 : case DTK_SECOND:
5312 : case DTK_MINUTE:
5313 : case DTK_HOUR:
5314 : case DTK_DAY:
5315 : case DTK_MONTH:
5316 : case DTK_QUARTER:
5317 : case DTK_WEEK:
5318 : case DTK_DOW:
5319 : case DTK_ISODOW:
5320 : case DTK_DOY:
5321 : case DTK_TZ:
5322 : case DTK_TZ_MINUTE:
5323 : case DTK_TZ_HOUR:
5324 396 : return 0.0;
5325 :
5326 : /* Monotonically-increasing units */
5327 216 : case DTK_YEAR:
5328 : case DTK_DECADE:
5329 : case DTK_CENTURY:
5330 : case DTK_MILLENNIUM:
5331 : case DTK_JULIAN:
5332 : case DTK_ISOYEAR:
5333 : case DTK_EPOCH:
5334 216 : if (isNegative)
5335 108 : return -get_float8_infinity();
5336 : else
5337 108 : return get_float8_infinity();
5338 :
5339 0 : default:
5340 0 : ereport(ERROR,
5341 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5342 : errmsg("unit \"%s\" not supported for type %s",
5343 : lowunits,
5344 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
5345 : return 0.0; /* keep compiler quiet */
5346 : }
5347 : }
5348 :
5349 : /* timestamp_part() and extract_timestamp()
5350 : * Extract specified field from timestamp.
5351 : */
5352 : static Datum
5353 10722 : timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5354 : {
5355 10722 : text *units = PG_GETARG_TEXT_PP(0);
5356 10722 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
5357 : int64 intresult;
5358 : Timestamp epoch;
5359 : int type,
5360 : val;
5361 : char *lowunits;
5362 : fsec_t fsec;
5363 : struct pg_tm tt,
5364 10722 : *tm = &tt;
5365 :
5366 10722 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5367 10722 : VARSIZE_ANY_EXHDR(units),
5368 : false);
5369 :
5370 10722 : type = DecodeUnits(0, lowunits, &val);
5371 10722 : if (type == UNKNOWN_FIELD)
5372 3714 : type = DecodeSpecial(0, lowunits, &val);
5373 :
5374 10722 : if (TIMESTAMP_NOT_FINITE(timestamp))
5375 : {
5376 288 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5377 : TIMESTAMP_IS_NOBEGIN(timestamp),
5378 : false);
5379 :
5380 288 : if (r != 0.0)
5381 : {
5382 108 : if (retnumeric)
5383 : {
5384 24 : if (r < 0)
5385 12 : return DirectFunctionCall3(numeric_in,
5386 : CStringGetDatum("-Infinity"),
5387 : ObjectIdGetDatum(InvalidOid),
5388 : Int32GetDatum(-1));
5389 12 : else if (r > 0)
5390 12 : return DirectFunctionCall3(numeric_in,
5391 : CStringGetDatum("Infinity"),
5392 : ObjectIdGetDatum(InvalidOid),
5393 : Int32GetDatum(-1));
5394 : }
5395 : else
5396 84 : PG_RETURN_FLOAT8(r);
5397 : }
5398 : else
5399 180 : PG_RETURN_NULL();
5400 : }
5401 :
5402 10434 : if (type == UNITS)
5403 : {
5404 9564 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
5405 0 : ereport(ERROR,
5406 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5407 : errmsg("timestamp out of range")));
5408 :
5409 9564 : switch (val)
5410 : {
5411 756 : case DTK_MICROSEC:
5412 756 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5413 756 : break;
5414 :
5415 756 : case DTK_MILLISEC:
5416 756 : if (retnumeric)
5417 : /*---
5418 : * tm->tm_sec * 1000 + fsec / 1000
5419 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5420 : */
5421 378 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5422 : else
5423 378 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5424 : break;
5425 :
5426 756 : case DTK_SECOND:
5427 756 : if (retnumeric)
5428 : /*---
5429 : * tm->tm_sec + fsec / 1'000'000
5430 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5431 : */
5432 378 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5433 : else
5434 378 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5435 : break;
5436 :
5437 378 : case DTK_MINUTE:
5438 378 : intresult = tm->tm_min;
5439 378 : break;
5440 :
5441 378 : case DTK_HOUR:
5442 378 : intresult = tm->tm_hour;
5443 378 : break;
5444 :
5445 474 : case DTK_DAY:
5446 474 : intresult = tm->tm_mday;
5447 474 : break;
5448 :
5449 474 : case DTK_MONTH:
5450 474 : intresult = tm->tm_mon;
5451 474 : break;
5452 :
5453 474 : case DTK_QUARTER:
5454 474 : intresult = (tm->tm_mon - 1) / 3 + 1;
5455 474 : break;
5456 :
5457 474 : case DTK_WEEK:
5458 474 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5459 474 : break;
5460 :
5461 474 : case DTK_YEAR:
5462 474 : if (tm->tm_year > 0)
5463 462 : intresult = tm->tm_year;
5464 : else
5465 : /* there is no year 0, just 1 BC and 1 AD */
5466 12 : intresult = tm->tm_year - 1;
5467 474 : break;
5468 :
5469 474 : case DTK_DECADE:
5470 :
5471 : /*
5472 : * what is a decade wrt dates? let us assume that decade 199
5473 : * is 1990 thru 1999... decade 0 starts on year 1 BC, and -1
5474 : * is 11 BC thru 2 BC...
5475 : */
5476 474 : if (tm->tm_year >= 0)
5477 462 : intresult = tm->tm_year / 10;
5478 : else
5479 12 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5480 474 : break;
5481 :
5482 474 : case DTK_CENTURY:
5483 :
5484 : /* ----
5485 : * centuries AD, c>0: year in [ (c-1)* 100 + 1 : c*100 ]
5486 : * centuries BC, c<0: year in [ c*100 : (c+1) * 100 - 1]
5487 : * there is no number 0 century.
5488 : * ----
5489 : */
5490 474 : if (tm->tm_year > 0)
5491 462 : intresult = (tm->tm_year + 99) / 100;
5492 : else
5493 : /* caution: C division may have negative remainder */
5494 12 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5495 474 : break;
5496 :
5497 474 : case DTK_MILLENNIUM:
5498 : /* see comments above. */
5499 474 : if (tm->tm_year > 0)
5500 462 : intresult = (tm->tm_year + 999) / 1000;
5501 : else
5502 12 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5503 474 : break;
5504 :
5505 852 : case DTK_JULIAN:
5506 852 : if (retnumeric)
5507 378 : PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5508 : 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),
5509 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5510 : NULL),
5511 : NULL));
5512 : else
5513 474 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5514 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5515 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5516 : break;
5517 :
5518 474 : case DTK_ISOYEAR:
5519 474 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5520 : /* Adjust BC years */
5521 474 : if (intresult <= 0)
5522 12 : intresult -= 1;
5523 474 : break;
5524 :
5525 948 : case DTK_DOW:
5526 : case DTK_ISODOW:
5527 948 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5528 948 : if (val == DTK_ISODOW && intresult == 0)
5529 30 : intresult = 7;
5530 948 : break;
5531 :
5532 474 : case DTK_DOY:
5533 474 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5534 474 : - date2j(tm->tm_year, 1, 1) + 1);
5535 474 : break;
5536 :
5537 0 : case DTK_TZ:
5538 : case DTK_TZ_MINUTE:
5539 : case DTK_TZ_HOUR:
5540 : default:
5541 0 : ereport(ERROR,
5542 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5543 : errmsg("unit \"%s\" not supported for type %s",
5544 : lowunits, format_type_be(TIMESTAMPOID))));
5545 : intresult = 0;
5546 : }
5547 : }
5548 870 : else if (type == RESERV)
5549 : {
5550 870 : switch (val)
5551 : {
5552 870 : case DTK_EPOCH:
5553 870 : epoch = SetEpochTimestamp();
5554 : /* (timestamp - epoch) / 1000000 */
5555 870 : if (retnumeric)
5556 : {
5557 : Numeric result;
5558 :
5559 390 : if (timestamp < (PG_INT64_MAX + epoch))
5560 384 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5561 : else
5562 : {
5563 6 : result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
5564 : int64_to_numeric(epoch),
5565 : NULL),
5566 : int64_to_numeric(1000000),
5567 : NULL);
5568 6 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5569 : NumericGetDatum(result),
5570 : Int32GetDatum(6)));
5571 : }
5572 390 : PG_RETURN_NUMERIC(result);
5573 : }
5574 : else
5575 : {
5576 : float8 result;
5577 :
5578 : /* try to avoid precision loss in subtraction */
5579 480 : if (timestamp < (PG_INT64_MAX + epoch))
5580 474 : result = (timestamp - epoch) / 1000000.0;
5581 : else
5582 6 : result = ((float8) timestamp - epoch) / 1000000.0;
5583 480 : PG_RETURN_FLOAT8(result);
5584 : }
5585 : break;
5586 :
5587 0 : default:
5588 0 : ereport(ERROR,
5589 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5590 : errmsg("unit \"%s\" not supported for type %s",
5591 : lowunits, format_type_be(TIMESTAMPOID))));
5592 : intresult = 0;
5593 : }
5594 : }
5595 : else
5596 : {
5597 0 : ereport(ERROR,
5598 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5599 : errmsg("unit \"%s\" not recognized for type %s",
5600 : lowunits, format_type_be(TIMESTAMPOID))));
5601 : intresult = 0;
5602 : }
5603 :
5604 7200 : if (retnumeric)
5605 378 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
5606 : else
5607 6822 : PG_RETURN_FLOAT8(intresult);
5608 : }
5609 :
5610 : Datum
5611 8760 : timestamp_part(PG_FUNCTION_ARGS)
5612 : {
5613 8760 : return timestamp_part_common(fcinfo, false);
5614 : }
5615 :
5616 : Datum
5617 1962 : extract_timestamp(PG_FUNCTION_ARGS)
5618 : {
5619 1962 : return timestamp_part_common(fcinfo, true);
5620 : }
5621 :
5622 : /* timestamptz_part() and extract_timestamptz()
5623 : * Extract specified field from timestamp with time zone.
5624 : */
5625 : static Datum
5626 37384 : timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5627 : {
5628 37384 : text *units = PG_GETARG_TEXT_PP(0);
5629 37384 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
5630 : int64 intresult;
5631 : Timestamp epoch;
5632 : int tz;
5633 : int type,
5634 : val;
5635 : char *lowunits;
5636 : fsec_t fsec;
5637 : struct pg_tm tt,
5638 37384 : *tm = &tt;
5639 :
5640 37384 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5641 37384 : VARSIZE_ANY_EXHDR(units),
5642 : false);
5643 :
5644 37384 : type = DecodeUnits(0, lowunits, &val);
5645 37384 : if (type == UNKNOWN_FIELD)
5646 29860 : type = DecodeSpecial(0, lowunits, &val);
5647 :
5648 37384 : if (TIMESTAMP_NOT_FINITE(timestamp))
5649 : {
5650 324 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
5651 : TIMESTAMP_IS_NOBEGIN(timestamp),
5652 : true);
5653 :
5654 324 : if (r != 0.0)
5655 : {
5656 108 : if (retnumeric)
5657 : {
5658 24 : if (r < 0)
5659 12 : return DirectFunctionCall3(numeric_in,
5660 : CStringGetDatum("-Infinity"),
5661 : ObjectIdGetDatum(InvalidOid),
5662 : Int32GetDatum(-1));
5663 12 : else if (r > 0)
5664 12 : return DirectFunctionCall3(numeric_in,
5665 : CStringGetDatum("Infinity"),
5666 : ObjectIdGetDatum(InvalidOid),
5667 : Int32GetDatum(-1));
5668 : }
5669 : else
5670 84 : PG_RETURN_FLOAT8(r);
5671 : }
5672 : else
5673 216 : PG_RETURN_NULL();
5674 : }
5675 :
5676 37060 : if (type == UNITS)
5677 : {
5678 9600 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
5679 0 : ereport(ERROR,
5680 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5681 : errmsg("timestamp out of range")));
5682 :
5683 9600 : switch (val)
5684 : {
5685 384 : case DTK_TZ:
5686 384 : intresult = -tz;
5687 384 : break;
5688 :
5689 384 : case DTK_TZ_MINUTE:
5690 384 : intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
5691 384 : break;
5692 :
5693 384 : case DTK_TZ_HOUR:
5694 384 : intresult = -tz / SECS_PER_HOUR;
5695 384 : break;
5696 :
5697 768 : case DTK_MICROSEC:
5698 768 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
5699 768 : break;
5700 :
5701 768 : case DTK_MILLISEC:
5702 768 : if (retnumeric)
5703 : /*---
5704 : * tm->tm_sec * 1000 + fsec / 1000
5705 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
5706 : */
5707 384 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5708 : else
5709 384 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5710 : break;
5711 :
5712 768 : case DTK_SECOND:
5713 768 : if (retnumeric)
5714 : /*---
5715 : * tm->tm_sec + fsec / 1'000'000
5716 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5717 : */
5718 384 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
5719 : else
5720 384 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
5721 : break;
5722 :
5723 384 : case DTK_MINUTE:
5724 384 : intresult = tm->tm_min;
5725 384 : break;
5726 :
5727 384 : case DTK_HOUR:
5728 384 : intresult = tm->tm_hour;
5729 384 : break;
5730 :
5731 384 : case DTK_DAY:
5732 384 : intresult = tm->tm_mday;
5733 384 : break;
5734 :
5735 384 : case DTK_MONTH:
5736 384 : intresult = tm->tm_mon;
5737 384 : break;
5738 :
5739 384 : case DTK_QUARTER:
5740 384 : intresult = (tm->tm_mon - 1) / 3 + 1;
5741 384 : break;
5742 :
5743 384 : case DTK_WEEK:
5744 384 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
5745 384 : break;
5746 :
5747 384 : case DTK_YEAR:
5748 384 : if (tm->tm_year > 0)
5749 378 : intresult = tm->tm_year;
5750 : else
5751 : /* there is no year 0, just 1 BC and 1 AD */
5752 6 : intresult = tm->tm_year - 1;
5753 384 : break;
5754 :
5755 384 : case DTK_DECADE:
5756 : /* see comments in timestamp_part */
5757 384 : if (tm->tm_year > 0)
5758 378 : intresult = tm->tm_year / 10;
5759 : else
5760 6 : intresult = -((8 - (tm->tm_year - 1)) / 10);
5761 384 : break;
5762 :
5763 384 : case DTK_CENTURY:
5764 : /* see comments in timestamp_part */
5765 384 : if (tm->tm_year > 0)
5766 378 : intresult = (tm->tm_year + 99) / 100;
5767 : else
5768 6 : intresult = -((99 - (tm->tm_year - 1)) / 100);
5769 384 : break;
5770 :
5771 384 : case DTK_MILLENNIUM:
5772 : /* see comments in timestamp_part */
5773 384 : if (tm->tm_year > 0)
5774 378 : intresult = (tm->tm_year + 999) / 1000;
5775 : else
5776 6 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
5777 384 : break;
5778 :
5779 768 : case DTK_JULIAN:
5780 768 : if (retnumeric)
5781 384 : PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
5782 : 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),
5783 : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
5784 : NULL),
5785 : NULL));
5786 : else
5787 384 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
5788 : ((((tm->tm_hour * MINS_PER_HOUR) + tm->tm_min) * SECS_PER_MINUTE) +
5789 : tm->tm_sec + (fsec / 1000000.0)) / (double) SECS_PER_DAY);
5790 : break;
5791 :
5792 384 : case DTK_ISOYEAR:
5793 384 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5794 : /* Adjust BC years */
5795 384 : if (intresult <= 0)
5796 6 : intresult -= 1;
5797 384 : break;
5798 :
5799 768 : case DTK_DOW:
5800 : case DTK_ISODOW:
5801 768 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
5802 768 : if (val == DTK_ISODOW && intresult == 0)
5803 18 : intresult = 7;
5804 768 : break;
5805 :
5806 384 : case DTK_DOY:
5807 384 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
5808 384 : - date2j(tm->tm_year, 1, 1) + 1);
5809 384 : break;
5810 :
5811 0 : default:
5812 0 : ereport(ERROR,
5813 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5814 : errmsg("unit \"%s\" not supported for type %s",
5815 : lowunits, format_type_be(TIMESTAMPTZOID))));
5816 : intresult = 0;
5817 : }
5818 : }
5819 27460 : else if (type == RESERV)
5820 : {
5821 27460 : switch (val)
5822 : {
5823 27460 : case DTK_EPOCH:
5824 27460 : epoch = SetEpochTimestamp();
5825 : /* (timestamp - epoch) / 1000000 */
5826 27460 : if (retnumeric)
5827 : {
5828 : Numeric result;
5829 :
5830 27070 : if (timestamp < (PG_INT64_MAX + epoch))
5831 27064 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
5832 : else
5833 : {
5834 6 : result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
5835 : int64_to_numeric(epoch),
5836 : NULL),
5837 : int64_to_numeric(1000000),
5838 : NULL);
5839 6 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5840 : NumericGetDatum(result),
5841 : Int32GetDatum(6)));
5842 : }
5843 27070 : PG_RETURN_NUMERIC(result);
5844 : }
5845 : else
5846 : {
5847 : float8 result;
5848 :
5849 : /* try to avoid precision loss in subtraction */
5850 390 : if (timestamp < (PG_INT64_MAX + epoch))
5851 384 : result = (timestamp - epoch) / 1000000.0;
5852 : else
5853 6 : result = ((float8) timestamp - epoch) / 1000000.0;
5854 390 : PG_RETURN_FLOAT8(result);
5855 : }
5856 : break;
5857 :
5858 0 : default:
5859 0 : ereport(ERROR,
5860 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5861 : errmsg("unit \"%s\" not supported for type %s",
5862 : lowunits, format_type_be(TIMESTAMPTZOID))));
5863 : intresult = 0;
5864 : }
5865 : }
5866 : else
5867 : {
5868 0 : ereport(ERROR,
5869 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5870 : errmsg("unit \"%s\" not recognized for type %s",
5871 : lowunits, format_type_be(TIMESTAMPTZOID))));
5872 :
5873 : intresult = 0;
5874 : }
5875 :
5876 7296 : if (retnumeric)
5877 384 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
5878 : else
5879 6912 : PG_RETURN_FLOAT8(intresult);
5880 : }
5881 :
5882 : Datum
5883 8718 : timestamptz_part(PG_FUNCTION_ARGS)
5884 : {
5885 8718 : return timestamptz_part_common(fcinfo, false);
5886 : }
5887 :
5888 : Datum
5889 28666 : extract_timestamptz(PG_FUNCTION_ARGS)
5890 : {
5891 28666 : return timestamptz_part_common(fcinfo, true);
5892 : }
5893 :
5894 : /*
5895 : * NonFiniteIntervalPart
5896 : *
5897 : * Used by interval_part when extracting from infinite interval. Returns
5898 : * +/-Infinity if that is the appropriate result, otherwise returns zero
5899 : * (which should be taken as meaning to return NULL).
5900 : *
5901 : * Errors thrown here for invalid units should exactly match those that
5902 : * would be thrown in the calling functions, else there will be unexpected
5903 : * discrepancies between finite- and infinite-input cases.
5904 : */
5905 : static float8
5906 204 : NonFiniteIntervalPart(int type, int unit, char *lowunits, bool isNegative)
5907 : {
5908 204 : if ((type != UNITS) && (type != RESERV))
5909 0 : ereport(ERROR,
5910 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5911 : errmsg("unit \"%s\" not recognized for type %s",
5912 : lowunits, format_type_be(INTERVALOID))));
5913 :
5914 204 : switch (unit)
5915 : {
5916 : /* Oscillating units */
5917 108 : case DTK_MICROSEC:
5918 : case DTK_MILLISEC:
5919 : case DTK_SECOND:
5920 : case DTK_MINUTE:
5921 : case DTK_MONTH:
5922 : case DTK_QUARTER:
5923 108 : return 0.0;
5924 :
5925 : /* Monotonically-increasing units */
5926 96 : case DTK_HOUR:
5927 : case DTK_DAY:
5928 : case DTK_YEAR:
5929 : case DTK_DECADE:
5930 : case DTK_CENTURY:
5931 : case DTK_MILLENNIUM:
5932 : case DTK_EPOCH:
5933 96 : if (isNegative)
5934 48 : return -get_float8_infinity();
5935 : else
5936 48 : return get_float8_infinity();
5937 :
5938 0 : default:
5939 0 : ereport(ERROR,
5940 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5941 : errmsg("unit \"%s\" not supported for type %s",
5942 : lowunits, format_type_be(INTERVALOID))));
5943 : return 0.0; /* keep compiler quiet */
5944 : }
5945 : }
5946 :
5947 : /* interval_part() and extract_interval()
5948 : * Extract specified field from interval.
5949 : */
5950 : static Datum
5951 1296 : interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5952 : {
5953 1296 : text *units = PG_GETARG_TEXT_PP(0);
5954 1296 : Interval *interval = PG_GETARG_INTERVAL_P(1);
5955 : int64 intresult;
5956 : int type,
5957 : val;
5958 : char *lowunits;
5959 : struct pg_itm tt,
5960 1296 : *tm = &tt;
5961 :
5962 1296 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5963 1296 : VARSIZE_ANY_EXHDR(units),
5964 : false);
5965 :
5966 1296 : type = DecodeUnits(0, lowunits, &val);
5967 1296 : if (type == UNKNOWN_FIELD)
5968 162 : type = DecodeSpecial(0, lowunits, &val);
5969 :
5970 1296 : if (INTERVAL_NOT_FINITE(interval))
5971 : {
5972 204 : double r = NonFiniteIntervalPart(type, val, lowunits,
5973 204 : INTERVAL_IS_NOBEGIN(interval));
5974 :
5975 204 : if (r != 0.0)
5976 : {
5977 96 : if (retnumeric)
5978 : {
5979 84 : if (r < 0)
5980 42 : return DirectFunctionCall3(numeric_in,
5981 : CStringGetDatum("-Infinity"),
5982 : ObjectIdGetDatum(InvalidOid),
5983 : Int32GetDatum(-1));
5984 42 : else if (r > 0)
5985 42 : return DirectFunctionCall3(numeric_in,
5986 : CStringGetDatum("Infinity"),
5987 : ObjectIdGetDatum(InvalidOid),
5988 : Int32GetDatum(-1));
5989 : }
5990 : else
5991 12 : PG_RETURN_FLOAT8(r);
5992 : }
5993 : else
5994 108 : PG_RETURN_NULL();
5995 : }
5996 :
5997 1092 : if (type == UNITS)
5998 : {
5999 954 : interval2itm(*interval, tm);
6000 954 : switch (val)
6001 : {
6002 120 : case DTK_MICROSEC:
6003 120 : intresult = tm->tm_sec * INT64CONST(1000000) + tm->tm_usec;
6004 120 : break;
6005 :
6006 120 : case DTK_MILLISEC:
6007 120 : if (retnumeric)
6008 : /*---
6009 : * tm->tm_sec * 1000 + fsec / 1000
6010 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
6011 : */
6012 60 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 3));
6013 : else
6014 60 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + tm->tm_usec / 1000.0);
6015 : break;
6016 :
6017 120 : case DTK_SECOND:
6018 120 : if (retnumeric)
6019 : /*---
6020 : * tm->tm_sec + fsec / 1'000'000
6021 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
6022 : */
6023 60 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 6));
6024 : else
6025 60 : PG_RETURN_FLOAT8(tm->tm_sec + tm->tm_usec / 1000000.0);
6026 : break;
6027 :
6028 60 : case DTK_MINUTE:
6029 60 : intresult = tm->tm_min;
6030 60 : break;
6031 :
6032 60 : case DTK_HOUR:
6033 60 : intresult = tm->tm_hour;
6034 60 : break;
6035 :
6036 60 : case DTK_DAY:
6037 60 : intresult = tm->tm_mday;
6038 60 : break;
6039 :
6040 60 : case DTK_MONTH:
6041 60 : intresult = tm->tm_mon;
6042 60 : break;
6043 :
6044 60 : case DTK_QUARTER:
6045 60 : intresult = (tm->tm_mon / 3) + 1;
6046 60 : break;
6047 :
6048 60 : case DTK_YEAR:
6049 60 : intresult = tm->tm_year;
6050 60 : break;
6051 :
6052 84 : case DTK_DECADE:
6053 : /* caution: C division may have negative remainder */
6054 84 : intresult = tm->tm_year / 10;
6055 84 : break;
6056 :
6057 84 : case DTK_CENTURY:
6058 : /* caution: C division may have negative remainder */
6059 84 : intresult = tm->tm_year / 100;
6060 84 : break;
6061 :
6062 60 : case DTK_MILLENNIUM:
6063 : /* caution: C division may have negative remainder */
6064 60 : intresult = tm->tm_year / 1000;
6065 60 : break;
6066 :
6067 6 : default:
6068 6 : ereport(ERROR,
6069 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6070 : errmsg("unit \"%s\" not supported for type %s",
6071 : lowunits, format_type_be(INTERVALOID))));
6072 : intresult = 0;
6073 : }
6074 : }
6075 138 : else if (type == RESERV && val == DTK_EPOCH)
6076 : {
6077 132 : if (retnumeric)
6078 : {
6079 : Numeric result;
6080 : int64 secs_from_day_month;
6081 : int64 val;
6082 :
6083 : /*
6084 : * To do this calculation in integer arithmetic even though
6085 : * DAYS_PER_YEAR is fractional, multiply everything by 4 and then
6086 : * divide by 4 again at the end. This relies on DAYS_PER_YEAR
6087 : * being a multiple of 0.25 and on SECS_PER_DAY being a multiple
6088 : * of 4.
6089 : */
6090 72 : secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) +
6091 72 : (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) +
6092 72 : (int64) 4 * interval->day) * (SECS_PER_DAY / 4);
6093 :
6094 : /*---
6095 : * result = secs_from_day_month + interval->time / 1'000'000
6096 : * = (secs_from_day_month * 1'000'000 + interval->time) / 1'000'000
6097 : */
6098 :
6099 : /*
6100 : * Try the computation inside int64; if it overflows, do it in
6101 : * numeric (slower). This overflow happens around 10^9 days, so
6102 : * not common in practice.
6103 : */
6104 72 : if (!pg_mul_s64_overflow(secs_from_day_month, 1000000, &val) &&
6105 66 : !pg_add_s64_overflow(val, interval->time, &val))
6106 66 : result = int64_div_fast_to_numeric(val, 6);
6107 : else
6108 : result =
6109 6 : numeric_add_opt_error(int64_div_fast_to_numeric(interval->time, 6),
6110 : int64_to_numeric(secs_from_day_month),
6111 : NULL);
6112 :
6113 72 : PG_RETURN_NUMERIC(result);
6114 : }
6115 : else
6116 : {
6117 : float8 result;
6118 :
6119 60 : result = interval->time / 1000000.0;
6120 60 : result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
6121 60 : result += ((double) DAYS_PER_MONTH * SECS_PER_DAY) * (interval->month % MONTHS_PER_YEAR);
6122 60 : result += ((double) SECS_PER_DAY) * interval->day;
6123 :
6124 60 : PG_RETURN_FLOAT8(result);
6125 : }
6126 : }
6127 : else
6128 : {
6129 6 : ereport(ERROR,
6130 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6131 : errmsg("unit \"%s\" not recognized for type %s",
6132 : lowunits, format_type_be(INTERVALOID))));
6133 : intresult = 0;
6134 : }
6135 :
6136 708 : if (retnumeric)
6137 648 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
6138 : else
6139 60 : PG_RETURN_FLOAT8(intresult);
6140 : }
6141 :
6142 : Datum
6143 288 : interval_part(PG_FUNCTION_ARGS)
6144 : {
6145 288 : return interval_part_common(fcinfo, false);
6146 : }
6147 :
6148 : Datum
6149 1008 : extract_interval(PG_FUNCTION_ARGS)
6150 : {
6151 1008 : return interval_part_common(fcinfo, true);
6152 : }
6153 :
6154 :
6155 : /* timestamp_zone()
6156 : * Encode timestamp type with specified time zone.
6157 : * This function is just timestamp2timestamptz() except instead of
6158 : * shifting to the global timezone, we shift to the specified timezone.
6159 : * This is different from the other AT TIME ZONE cases because instead
6160 : * of shifting _to_ a new time zone, it sets the time to _be_ the
6161 : * specified timezone.
6162 : */
6163 : Datum
6164 168 : timestamp_zone(PG_FUNCTION_ARGS)
6165 : {
6166 168 : text *zone = PG_GETARG_TEXT_PP(0);
6167 168 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6168 : TimestampTz result;
6169 : int tz;
6170 : char tzname[TZ_STRLEN_MAX + 1];
6171 : int type,
6172 : val;
6173 : pg_tz *tzp;
6174 : struct pg_tm tm;
6175 : fsec_t fsec;
6176 :
6177 168 : if (TIMESTAMP_NOT_FINITE(timestamp))
6178 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6179 :
6180 : /*
6181 : * Look up the requested timezone.
6182 : */
6183 168 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6184 :
6185 168 : type = DecodeTimezoneName(tzname, &val, &tzp);
6186 :
6187 168 : if (type == TZNAME_FIXED_OFFSET)
6188 : {
6189 : /* fixed-offset abbreviation */
6190 0 : tz = val;
6191 0 : result = dt2local(timestamp, tz);
6192 : }
6193 168 : else if (type == TZNAME_DYNTZ)
6194 : {
6195 : /* dynamic-offset abbreviation, resolve using specified time */
6196 84 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6197 0 : ereport(ERROR,
6198 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6199 : errmsg("timestamp out of range")));
6200 84 : tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
6201 84 : result = dt2local(timestamp, tz);
6202 : }
6203 : else
6204 : {
6205 : /* full zone name, rotate to that zone */
6206 84 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6207 0 : ereport(ERROR,
6208 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6209 : errmsg("timestamp out of range")));
6210 84 : tz = DetermineTimeZoneOffset(&tm, tzp);
6211 84 : if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
6212 0 : ereport(ERROR,
6213 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6214 : errmsg("timestamp out of range")));
6215 : }
6216 :
6217 168 : if (!IS_VALID_TIMESTAMP(result))
6218 0 : ereport(ERROR,
6219 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6220 : errmsg("timestamp out of range")));
6221 :
6222 168 : PG_RETURN_TIMESTAMPTZ(result);
6223 : }
6224 :
6225 : /* timestamp_izone()
6226 : * Encode timestamp type with specified time interval as time zone.
6227 : */
6228 : Datum
6229 12 : timestamp_izone(PG_FUNCTION_ARGS)
6230 : {
6231 12 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6232 12 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
6233 : TimestampTz result;
6234 : int tz;
6235 :
6236 12 : if (TIMESTAMP_NOT_FINITE(timestamp))
6237 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
6238 :
6239 12 : if (INTERVAL_NOT_FINITE(zone))
6240 12 : ereport(ERROR,
6241 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6242 : errmsg("interval time zone \"%s\" must be finite",
6243 : DatumGetCString(DirectFunctionCall1(interval_out,
6244 : PointerGetDatum(zone))))));
6245 :
6246 0 : if (zone->month != 0 || zone->day != 0)
6247 0 : ereport(ERROR,
6248 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6249 : errmsg("interval time zone \"%s\" must not include months or days",
6250 : DatumGetCString(DirectFunctionCall1(interval_out,
6251 : PointerGetDatum(zone))))));
6252 :
6253 0 : tz = zone->time / USECS_PER_SEC;
6254 :
6255 0 : result = dt2local(timestamp, tz);
6256 :
6257 0 : if (!IS_VALID_TIMESTAMP(result))
6258 0 : ereport(ERROR,
6259 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6260 : errmsg("timestamp out of range")));
6261 :
6262 0 : PG_RETURN_TIMESTAMPTZ(result);
6263 : } /* timestamp_izone() */
6264 :
6265 : /* TimestampTimestampTzRequiresRewrite()
6266 : *
6267 : * Returns false if the TimeZone GUC setting causes timestamp_timestamptz and
6268 : * timestamptz_timestamp to be no-ops, where the return value has the same
6269 : * bits as the argument. Since project convention is to assume a GUC changes
6270 : * no more often than STABLE functions change, the answer is valid that long.
6271 : */
6272 : bool
6273 18 : TimestampTimestampTzRequiresRewrite(void)
6274 : {
6275 : long offset;
6276 :
6277 18 : if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
6278 12 : return false;
6279 6 : return true;
6280 : }
6281 :
6282 : /* timestamp_timestamptz()
6283 : * Convert local timestamp to timestamp at GMT
6284 : */
6285 : Datum
6286 216 : timestamp_timestamptz(PG_FUNCTION_ARGS)
6287 : {
6288 216 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
6289 :
6290 216 : PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
6291 : }
6292 :
6293 : /*
6294 : * Convert timestamp to timestamp with time zone.
6295 : *
6296 : * On successful conversion, *overflow is set to zero if it's not NULL.
6297 : *
6298 : * If the timestamp is finite but out of the valid range for timestamptz, then:
6299 : * if overflow is NULL, we throw an out-of-range error.
6300 : * if overflow is not NULL, we store +1 or -1 there to indicate the sign
6301 : * of the overflow, and return the appropriate timestamptz infinity.
6302 : */
6303 : TimestampTz
6304 16128 : timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
6305 : {
6306 : TimestampTz result;
6307 : struct pg_tm tt,
6308 16128 : *tm = &tt;
6309 : fsec_t fsec;
6310 : int tz;
6311 :
6312 16128 : if (overflow)
6313 15906 : *overflow = 0;
6314 :
6315 16128 : if (TIMESTAMP_NOT_FINITE(timestamp))
6316 0 : return timestamp;
6317 :
6318 : /* We don't expect this to fail, but check it pro forma */
6319 16128 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
6320 : {
6321 16128 : tz = DetermineTimeZoneOffset(tm, session_timezone);
6322 :
6323 16128 : result = dt2local(timestamp, -tz);
6324 :
6325 16128 : if (IS_VALID_TIMESTAMP(result))
6326 : {
6327 16116 : return result;
6328 : }
6329 12 : else if (overflow)
6330 : {
6331 12 : if (result < MIN_TIMESTAMP)
6332 : {
6333 12 : *overflow = -1;
6334 12 : TIMESTAMP_NOBEGIN(result);
6335 : }
6336 : else
6337 : {
6338 0 : *overflow = 1;
6339 0 : TIMESTAMP_NOEND(result);
6340 : }
6341 12 : return result;
6342 : }
6343 : }
6344 :
6345 0 : ereport(ERROR,
6346 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6347 : errmsg("timestamp out of range")));
6348 :
6349 : return 0;
6350 : }
6351 :
6352 : /*
6353 : * Promote timestamp to timestamptz, throwing error for overflow.
6354 : */
6355 : static TimestampTz
6356 222 : timestamp2timestamptz(Timestamp timestamp)
6357 : {
6358 222 : return timestamp2timestamptz_opt_overflow(timestamp, NULL);
6359 : }
6360 :
6361 : /* timestamptz_timestamp()
6362 : * Convert timestamp at GMT to local timestamp
6363 : */
6364 : Datum
6365 62104 : timestamptz_timestamp(PG_FUNCTION_ARGS)
6366 : {
6367 62104 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
6368 :
6369 62104 : PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
6370 : }
6371 :
6372 : static Timestamp
6373 62170 : timestamptz2timestamp(TimestampTz timestamp)
6374 : {
6375 : Timestamp result;
6376 : struct pg_tm tt,
6377 62170 : *tm = &tt;
6378 : fsec_t fsec;
6379 : int tz;
6380 :
6381 62170 : if (TIMESTAMP_NOT_FINITE(timestamp))
6382 0 : result = timestamp;
6383 : else
6384 : {
6385 62170 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
6386 0 : ereport(ERROR,
6387 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6388 : errmsg("timestamp out of range")));
6389 62170 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
6390 0 : ereport(ERROR,
6391 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6392 : errmsg("timestamp out of range")));
6393 : }
6394 62170 : return result;
6395 : }
6396 :
6397 : /* timestamptz_zone()
6398 : * Evaluate timestamp with time zone type at the specified time zone.
6399 : * Returns a timestamp without time zone.
6400 : */
6401 : Datum
6402 222 : timestamptz_zone(PG_FUNCTION_ARGS)
6403 : {
6404 222 : text *zone = PG_GETARG_TEXT_PP(0);
6405 222 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6406 : Timestamp result;
6407 : int tz;
6408 : char tzname[TZ_STRLEN_MAX + 1];
6409 : int type,
6410 : val;
6411 : pg_tz *tzp;
6412 :
6413 222 : if (TIMESTAMP_NOT_FINITE(timestamp))
6414 24 : PG_RETURN_TIMESTAMP(timestamp);
6415 :
6416 : /*
6417 : * Look up the requested timezone.
6418 : */
6419 198 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
6420 :
6421 198 : type = DecodeTimezoneName(tzname, &val, &tzp);
6422 :
6423 192 : if (type == TZNAME_FIXED_OFFSET)
6424 : {
6425 : /* fixed-offset abbreviation */
6426 36 : tz = -val;
6427 36 : result = dt2local(timestamp, tz);
6428 : }
6429 156 : else if (type == TZNAME_DYNTZ)
6430 : {
6431 : /* dynamic-offset abbreviation, resolve using specified time */
6432 : int isdst;
6433 :
6434 72 : tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
6435 72 : result = dt2local(timestamp, tz);
6436 : }
6437 : else
6438 : {
6439 : /* full zone name, rotate from that zone */
6440 : struct pg_tm tm;
6441 : fsec_t fsec;
6442 :
6443 84 : if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
6444 0 : ereport(ERROR,
6445 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6446 : errmsg("timestamp out of range")));
6447 84 : if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
6448 0 : ereport(ERROR,
6449 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6450 : errmsg("timestamp out of range")));
6451 : }
6452 :
6453 192 : if (!IS_VALID_TIMESTAMP(result))
6454 0 : ereport(ERROR,
6455 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6456 : errmsg("timestamp out of range")));
6457 :
6458 192 : PG_RETURN_TIMESTAMP(result);
6459 : }
6460 :
6461 : /* timestamptz_izone()
6462 : * Encode timestamp with time zone type with specified time interval as time zone.
6463 : * Returns a timestamp without time zone.
6464 : */
6465 : Datum
6466 12 : timestamptz_izone(PG_FUNCTION_ARGS)
6467 : {
6468 12 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6469 12 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
6470 : Timestamp result;
6471 : int tz;
6472 :
6473 12 : if (TIMESTAMP_NOT_FINITE(timestamp))
6474 0 : PG_RETURN_TIMESTAMP(timestamp);
6475 :
6476 12 : if (INTERVAL_NOT_FINITE(zone))
6477 12 : ereport(ERROR,
6478 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6479 : errmsg("interval time zone \"%s\" must be finite",
6480 : DatumGetCString(DirectFunctionCall1(interval_out,
6481 : PointerGetDatum(zone))))));
6482 :
6483 0 : if (zone->month != 0 || zone->day != 0)
6484 0 : ereport(ERROR,
6485 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6486 : errmsg("interval time zone \"%s\" must not include months or days",
6487 : DatumGetCString(DirectFunctionCall1(interval_out,
6488 : PointerGetDatum(zone))))));
6489 :
6490 0 : tz = -(zone->time / USECS_PER_SEC);
6491 :
6492 0 : result = dt2local(timestamp, tz);
6493 :
6494 0 : if (!IS_VALID_TIMESTAMP(result))
6495 0 : ereport(ERROR,
6496 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6497 : errmsg("timestamp out of range")));
6498 :
6499 0 : PG_RETURN_TIMESTAMP(result);
6500 : }
6501 :
6502 : /* generate_series_timestamp()
6503 : * Generate the set of timestamps from start to finish by step
6504 : */
6505 : Datum
6506 498 : generate_series_timestamp(PG_FUNCTION_ARGS)
6507 : {
6508 : FuncCallContext *funcctx;
6509 : generate_series_timestamp_fctx *fctx;
6510 : Timestamp result;
6511 :
6512 : /* stuff done only on the first call of the function */
6513 498 : if (SRF_IS_FIRSTCALL())
6514 : {
6515 36 : Timestamp start = PG_GETARG_TIMESTAMP(0);
6516 36 : Timestamp finish = PG_GETARG_TIMESTAMP(1);
6517 36 : Interval *step = PG_GETARG_INTERVAL_P(2);
6518 : MemoryContext oldcontext;
6519 :
6520 : /* create a function context for cross-call persistence */
6521 36 : funcctx = SRF_FIRSTCALL_INIT();
6522 :
6523 : /*
6524 : * switch to memory context appropriate for multiple function calls
6525 : */
6526 36 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6527 :
6528 : /* allocate memory for user context */
6529 : fctx = (generate_series_timestamp_fctx *)
6530 36 : palloc(sizeof(generate_series_timestamp_fctx));
6531 :
6532 : /*
6533 : * Use fctx to keep state from call to call. Seed current with the
6534 : * original start value
6535 : */
6536 36 : fctx->current = start;
6537 36 : fctx->finish = finish;
6538 36 : fctx->step = *step;
6539 :
6540 : /* Determine sign of the interval */
6541 36 : fctx->step_sign = interval_sign(&fctx->step);
6542 :
6543 36 : if (fctx->step_sign == 0)
6544 6 : ereport(ERROR,
6545 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6546 : errmsg("step size cannot equal zero")));
6547 :
6548 30 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6549 12 : ereport(ERROR,
6550 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6551 : errmsg("step size cannot be infinite")));
6552 :
6553 18 : funcctx->user_fctx = fctx;
6554 18 : MemoryContextSwitchTo(oldcontext);
6555 : }
6556 :
6557 : /* stuff done on every call of the function */
6558 480 : funcctx = SRF_PERCALL_SETUP();
6559 :
6560 : /*
6561 : * get the saved state and use current as the result for this iteration
6562 : */
6563 480 : fctx = funcctx->user_fctx;
6564 480 : result = fctx->current;
6565 :
6566 960 : if (fctx->step_sign > 0 ?
6567 480 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6568 0 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6569 : {
6570 : /* increment current in preparation for next iteration */
6571 468 : fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
6572 : TimestampGetDatum(fctx->current),
6573 : PointerGetDatum(&fctx->step)));
6574 :
6575 : /* do when there is more left to send */
6576 468 : SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
6577 : }
6578 : else
6579 : {
6580 : /* do when there is no more left */
6581 12 : SRF_RETURN_DONE(funcctx);
6582 : }
6583 : }
6584 :
6585 : /* generate_series_timestamptz()
6586 : * Generate the set of timestamps from start to finish by step,
6587 : * doing arithmetic in the specified or session timezone.
6588 : */
6589 : static Datum
6590 62076 : generate_series_timestamptz_internal(FunctionCallInfo fcinfo)
6591 : {
6592 : FuncCallContext *funcctx;
6593 : generate_series_timestamptz_fctx *fctx;
6594 : TimestampTz result;
6595 :
6596 : /* stuff done only on the first call of the function */
6597 62076 : if (SRF_IS_FIRSTCALL())
6598 : {
6599 56 : TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
6600 56 : TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
6601 56 : Interval *step = PG_GETARG_INTERVAL_P(2);
6602 56 : text *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
6603 : MemoryContext oldcontext;
6604 :
6605 : /* create a function context for cross-call persistence */
6606 56 : funcctx = SRF_FIRSTCALL_INIT();
6607 :
6608 : /*
6609 : * switch to memory context appropriate for multiple function calls
6610 : */
6611 56 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
6612 :
6613 : /* allocate memory for user context */
6614 : fctx = (generate_series_timestamptz_fctx *)
6615 56 : palloc(sizeof(generate_series_timestamptz_fctx));
6616 :
6617 : /*
6618 : * Use fctx to keep state from call to call. Seed current with the
6619 : * original start value
6620 : */
6621 56 : fctx->current = start;
6622 56 : fctx->finish = finish;
6623 56 : fctx->step = *step;
6624 56 : fctx->attimezone = zone ? lookup_timezone(zone) : session_timezone;
6625 :
6626 : /* Determine sign of the interval */
6627 56 : fctx->step_sign = interval_sign(&fctx->step);
6628 :
6629 56 : if (fctx->step_sign == 0)
6630 6 : ereport(ERROR,
6631 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6632 : errmsg("step size cannot equal zero")));
6633 :
6634 50 : if (INTERVAL_NOT_FINITE((&fctx->step)))
6635 12 : ereport(ERROR,
6636 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6637 : errmsg("step size cannot be infinite")));
6638 :
6639 38 : funcctx->user_fctx = fctx;
6640 38 : MemoryContextSwitchTo(oldcontext);
6641 : }
6642 :
6643 : /* stuff done on every call of the function */
6644 62058 : funcctx = SRF_PERCALL_SETUP();
6645 :
6646 : /*
6647 : * get the saved state and use current as the result for this iteration
6648 : */
6649 62058 : fctx = funcctx->user_fctx;
6650 62058 : result = fctx->current;
6651 :
6652 124116 : if (fctx->step_sign > 0 ?
6653 61974 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
6654 84 : timestamp_cmp_internal(result, fctx->finish) >= 0)
6655 : {
6656 : /* increment current in preparation for next iteration */
6657 62026 : fctx->current = timestamptz_pl_interval_internal(fctx->current,
6658 : &fctx->step,
6659 : fctx->attimezone);
6660 :
6661 : /* do when there is more left to send */
6662 62026 : SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
6663 : }
6664 : else
6665 : {
6666 : /* do when there is no more left */
6667 32 : SRF_RETURN_DONE(funcctx);
6668 : }
6669 : }
6670 :
6671 : Datum
6672 61992 : generate_series_timestamptz(PG_FUNCTION_ARGS)
6673 : {
6674 61992 : return generate_series_timestamptz_internal(fcinfo);
6675 : }
6676 :
6677 : Datum
6678 84 : generate_series_timestamptz_at_zone(PG_FUNCTION_ARGS)
6679 : {
6680 84 : return generate_series_timestamptz_internal(fcinfo);
6681 : }
6682 :
6683 : /* timestamp_at_local()
6684 : * timestamptz_at_local()
6685 : *
6686 : * The regression tests do not like two functions with the same proargs and
6687 : * prosrc but different proname, but the grammar for AT LOCAL needs an
6688 : * overloaded name to handle both types of timestamp, so we make simple
6689 : * wrappers for it.
6690 : */
6691 : Datum
6692 24 : timestamp_at_local(PG_FUNCTION_ARGS)
6693 : {
6694 24 : return timestamp_timestamptz(fcinfo);
6695 : }
6696 :
6697 : Datum
6698 24 : timestamptz_at_local(PG_FUNCTION_ARGS)
6699 : {
6700 24 : return timestamptz_timestamp(fcinfo);
6701 : }
|