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