Age Owner 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
2427 tgl 86 GIC 338 : anytimestamp_typmod_check(bool istz, int32 typmod)
87 : {
2427 tgl 88 CBC 338 : if (typmod < 0)
5944 tgl 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" : ""))));
2427 tgl 93 CBC 338 : if (typmod > MAX_TIMESTAMP_PRECISION)
94 : {
5944 tgl 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" : ""),
2118 tgl 99 ECB : MAX_TIMESTAMP_PRECISION)));
5944 tgl 100 GBC 6 : typmod = MAX_TIMESTAMP_PRECISION;
101 : }
102 :
5944 tgl 103 GIC 338 : return typmod;
5944 tgl 104 ECB : }
105 :
106 : static int32
139 michael 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)
139 michael 119 UNC 0 : ereport(ERROR,
120 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
121 : errmsg("invalid type modifier")));
122 :
139 michael 123 GNC 329 : return anytimestamp_typmod_check(istz, tl[0]);
124 : }
125 :
126 : /* common code for timestamptypmodout and timestamptztypmodout */
127 : static char *
5944 tgl 128 GIC 10 : anytimestamp_typmodout(bool istz, int32 typmod)
5944 tgl 129 ECB : {
5944 tgl 130 GIC 10 : const char *tz = istz ? " with time zone" : " without time zone";
5944 tgl 131 ECB :
5944 tgl 132 GIC 10 : if (typmod >= 0)
3380 peter_e 133 CBC 10 : return psprintf("(%d)%s", (int) typmod, tz);
5944 tgl 134 ECB : else
215 drowley 135 UNC 0 : return pstrdup(tz);
5944 tgl 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
8339 tgl 147 GIC 9010 : timestamp_in(PG_FUNCTION_ARGS)
9522 scrappy 148 ECB : {
8339 tgl 149 GIC 9010 : char *str = PG_GETARG_CSTRING(0);
150 : #ifdef NOT_USED
151 : Oid typelem = PG_GETARG_OID(1);
152 : #endif
7858 lockhart 153 CBC 9010 : int32 typmod = PG_GETARG_INT32(2);
121 tgl 154 GNC 9010 : Node *escontext = fcinfo->context;
8339 tgl 155 ECB : Timestamp result;
156 : fsec_t fsec;
157 : struct pg_tm tt,
8453 lockhart 158 GIC 9010 : *tm = &tt;
8453 lockhart 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 :
6527 neilc 168 GIC 9010 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
169 : field, ftype, MAXDATEFIELDS, &nf);
7165 tgl 170 CBC 9010 : if (dterr == 0)
121 tgl 171 GNC 9010 : dterr = DecodeDateTime(field, ftype, nf,
172 : &dtype, tm, &fsec, &tz, &extra);
7165 tgl 173 CBC 9010 : if (dterr != 0)
174 : {
121 tgl 175 GNC 57 : DateTimeParseError(dterr, &extra, str, "timestamp", escontext);
176 12 : PG_RETURN_NULL();
177 : }
178 :
8453 lockhart 179 CBC 8953 : switch (dtype)
180 : {
181 8887 : case DTK_DATE:
7863 182 8887 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
121 tgl 183 GNC 9 : ereturn(escontext, (Datum) 0,
184 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 185 ECB : errmsg("timestamp out of range: \"%s\"", str)));
8453 lockhart 186 GIC 8878 : break;
8453 lockhart 187 ECB :
8453 lockhart 188 CBC 12 : case DTK_EPOCH:
7863 189 12 : result = SetEpochTimestamp();
8453 lockhart 190 GIC 12 : break;
191 :
8453 lockhart 192 CBC 37 : case DTK_LATE:
8339 tgl 193 GIC 37 : TIMESTAMP_NOEND(result);
8453 lockhart 194 CBC 37 : break;
8453 lockhart 195 ECB :
8453 lockhart 196 CBC 17 : case DTK_EARLY:
8339 tgl 197 GIC 17 : TIMESTAMP_NOBEGIN(result);
8453 lockhart 198 CBC 17 : break;
8453 lockhart 199 ECB :
8453 lockhart 200 LBC 0 : default:
7196 tgl 201 UIC 0 : elog(ERROR, "unexpected dtype %d while parsing timestamp \"%s\"",
7196 tgl 202 ECB : dtype, str);
7863 lockhart 203 : TIMESTAMP_NOEND(result);
8453 204 : }
205 :
121 tgl 206 GNC 8944 : AdjustTimestampForTypmod(&result, typmod, escontext);
7858 lockhart 207 EUB :
8339 tgl 208 GIC 8944 : PG_RETURN_TIMESTAMP(result);
209 : }
210 :
211 : /* timestamp_out()
8453 lockhart 212 ECB : * Convert a timestamp to external form.
213 : */
8339 tgl 214 : Datum
8339 tgl 215 GIC 21572 : timestamp_out(PG_FUNCTION_ARGS)
216 : {
6385 bruce 217 21572 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
218 : char *result;
219 : struct pg_tm tt,
7863 lockhart 220 21572 : *tm = &tt;
7658 lockhart 221 ECB : fsec_t fsec;
222 : char buf[MAXDATELEN + 1];
7863 223 :
7858 lockhart 224 GIC 21572 : if (TIMESTAMP_NOT_FINITE(timestamp))
225 110 : EncodeSpecialTimestamp(timestamp, buf);
6507 bruce 226 CBC 21462 : else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
4043 peter_e 227 GIC 21462 : EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf);
228 : else
7196 tgl 229 UIC 0 : ereport(ERROR,
7196 tgl 230 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
231 : errmsg("timestamp out of range")));
7863 lockhart 232 :
7863 lockhart 233 CBC 21572 : result = pstrdup(buf);
7863 lockhart 234 GIC 21572 : PG_RETURN_CSTRING(result);
7863 lockhart 235 EUB : }
236 :
237 : /*
238 : * timestamp_recv - converts external binary format to timestamp
7272 tgl 239 ECB : */
240 : Datum
7272 tgl 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);
6482 tgl 247 EUB : #endif
6482 tgl 248 UIC 0 : int32 typmod = PG_GETARG_INT32(2);
6385 bruce 249 EUB : Timestamp timestamp;
250 : struct pg_tm tt,
6884 tgl 251 UIC 0 : *tm = &tt;
252 : fsec_t fsec;
253 :
6884 tgl 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 */ ;
2580 tgl 259 UIC 0 : else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0 ||
2580 tgl 260 UBC 0 : !IS_VALID_TIMESTAMP(timestamp))
6884 tgl 261 UIC 0 : ereport(ERROR,
262 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6884 tgl 263 EUB : errmsg("timestamp out of range")));
264 :
121 tgl 265 UNC 0 : AdjustTimestampForTypmod(×tamp, typmod, NULL);
6482 tgl 266 EUB :
6884 tgl 267 UBC 0 : PG_RETURN_TIMESTAMP(timestamp);
268 : }
269 :
270 : /*
7272 tgl 271 EUB : * timestamp_send - converts timestamp to binary format
272 : */
273 : Datum
7272 tgl 274 UIC 0 : timestamp_send(PG_FUNCTION_ARGS)
275 : {
6385 bruce 276 0 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
277 : StringInfoData buf;
278 :
7272 tgl 279 0 : pq_begintypsend(&buf);
7272 tgl 280 UBC 0 : pq_sendint64(&buf, timestamp);
7272 tgl 281 UIC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
7272 tgl 282 EUB : }
283 :
284 : Datum
5944 tgl 285 GBC 15 : timestamptypmodin(PG_FUNCTION_ARGS)
5944 tgl 286 EUB : {
5624 bruce 287 GBC 15 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
288 :
5944 tgl 289 GIC 15 : PG_RETURN_INT32(anytimestamp_typmodin(false, ta));
290 : }
5944 tgl 291 ECB :
292 : Datum
5944 tgl 293 CBC 5 : timestamptypmodout(PG_FUNCTION_ARGS)
294 : {
5624 bruce 295 5 : int32 typmod = PG_GETARG_INT32(0);
296 :
5944 tgl 297 GIC 5 : PG_RETURN_CSTRING(anytimestamp_typmodout(false, typmod));
298 : }
5944 tgl 299 ECB :
300 :
1520 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
1520 tgl 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))
1520 tgl 314 ECB : {
1520 tgl 315 GIC 6 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1520 tgl 316 ECB :
1520 tgl 317 CBC 6 : ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall);
318 : }
1520 tgl 319 ECB :
1520 tgl 320 GIC 12 : PG_RETURN_POINTER(ret);
4078 rhaas 321 ECB : }
322 :
7858 lockhart 323 : /* timestamp_scale()
324 : * Adjust time type for specified scale factor.
325 : * Used by PostgreSQL type system to stuff columns.
326 : */
327 : Datum
7858 lockhart 328 GIC 31086 : timestamp_scale(PG_FUNCTION_ARGS)
329 : {
6385 bruce 330 31086 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
7858 lockhart 331 31086 : int32 typmod = PG_GETARG_INT32(1);
332 : Timestamp result;
333 :
7858 lockhart 334 CBC 31086 : result = timestamp;
335 :
121 tgl 336 GNC 31086 : AdjustTimestampForTypmod(&result, typmod, NULL);
7858 lockhart 337 ECB :
7858 lockhart 338 GIC 31086 : PG_RETURN_TIMESTAMP(result);
339 : }
7858 lockhart 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).
2427 tgl 347 : */
348 : bool
121 tgl 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),
7658 lockhart 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 :
7658 lockhart 371 GIC 62132 : if (!TIMESTAMP_NOT_FINITE(*time)
372 62007 : && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
373 : {
6530 bruce 374 31396 : if (typmod < 0 || typmod > MAX_TIMESTAMP_PRECISION)
121 tgl 375 UNC 0 : ereturn(escontext, false,
7196 tgl 376 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2118 tgl 377 EUB : errmsg("timestamp(%d) precision must be between %d and %d",
378 : typmod, 0, MAX_TIMESTAMP_PRECISION)));
379 :
7658 lockhart 380 GIC 31396 : if (*time >= INT64CONST(0))
7658 lockhart 381 ECB : {
6529 bruce 382 GIC 31075 : *time = ((*time + TimestampOffsets[typmod]) / TimestampScales[typmod]) *
6385 bruce 383 CBC 31075 : TimestampScales[typmod];
7658 lockhart 384 ECB : }
385 : else
386 : {
7188 bruce 387 GIC 321 : *time = -((((-*time) + TimestampOffsets[typmod]) / TimestampScales[typmod])
7188 bruce 388 CBC 321 : * TimestampScales[typmod]);
7658 lockhart 389 ECB : }
390 : }
391 :
1292 akorotkov 392 GIC 62132 : return true;
7858 lockhart 393 ECB : }
394 :
395 : /* timestamptz_in()
7863 396 : * Convert a string to internal form.
397 : */
398 : Datum
7863 lockhart 399 GIC 21157 : timestamptz_in(PG_FUNCTION_ARGS)
7863 lockhart 400 ECB : {
7863 lockhart 401 CBC 21157 : char *str = PG_GETARG_CSTRING(0);
402 : #ifdef NOT_USED
403 : Oid typelem = PG_GETARG_OID(1);
7858 lockhart 404 ECB : #endif
7858 lockhart 405 GIC 21157 : int32 typmod = PG_GETARG_INT32(2);
121 tgl 406 GNC 21157 : Node *escontext = fcinfo->context;
407 : TimestampTz result;
408 : fsec_t fsec;
409 : struct pg_tm tt,
7863 lockhart 410 GIC 21157 : *tm = &tt;
411 : int tz;
412 : int dtype;
413 : int nf;
414 : int dterr;
7863 lockhart 415 ECB : char *field[MAXDATEFIELDS];
416 : int ftype[MAXDATEFIELDS];
6527 neilc 417 : char workbuf[MAXDATELEN + MAXDATEFIELDS];
418 : DateTimeErrorExtra extra;
7553 lockhart 419 :
6527 neilc 420 GIC 21157 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
6527 neilc 421 ECB : field, ftype, MAXDATEFIELDS, &nf);
7165 tgl 422 GIC 21157 : if (dterr == 0)
121 tgl 423 GNC 21157 : dterr = DecodeDateTime(field, ftype, nf,
424 : &dtype, tm, &fsec, &tz, &extra);
7165 tgl 425 GIC 21157 : if (dterr != 0)
426 : {
121 tgl 427 GNC 54 : DateTimeParseError(dterr, &extra, str, "timestamp with time zone",
428 : escontext);
429 12 : PG_RETURN_NULL();
430 : }
431 :
7863 lockhart 432 GIC 21103 : switch (dtype)
7863 lockhart 433 ECB : {
7863 lockhart 434 GIC 21038 : case DTK_DATE:
7863 lockhart 435 CBC 21038 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
121 tgl 436 GNC 12 : ereturn(escontext, (Datum) 0,
7196 tgl 437 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
438 : errmsg("timestamp out of range: \"%s\"", str)));
7863 lockhart 439 GIC 21026 : break;
7863 lockhart 440 ECB :
7863 lockhart 441 GIC 6 : case DTK_EPOCH:
7863 lockhart 442 CBC 6 : result = SetEpochTimestamp();
443 6 : break;
7863 lockhart 444 ECB :
7863 lockhart 445 GIC 39 : case DTK_LATE:
7863 lockhart 446 CBC 39 : TIMESTAMP_NOEND(result);
447 39 : break;
7863 lockhart 448 ECB :
7863 lockhart 449 GIC 20 : case DTK_EARLY:
7863 lockhart 450 CBC 20 : TIMESTAMP_NOBEGIN(result);
451 20 : break;
7863 lockhart 452 ECB :
7863 lockhart 453 UIC 0 : default:
7196 tgl 454 UBC 0 : elog(ERROR, "unexpected dtype %d while parsing timestamptz \"%s\"",
7196 tgl 455 EUB : dtype, str);
456 : TIMESTAMP_NOEND(result);
457 : }
458 :
121 tgl 459 GNC 21091 : AdjustTimestampForTypmod(&result, typmod, escontext);
7858 lockhart 460 ECB :
7863 lockhart 461 GIC 21091 : PG_RETURN_TIMESTAMPTZ(result);
7863 lockhart 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
2118 tgl 472 GIC 93 : parse_sane_timezone(struct pg_tm *tm, text *zone)
3323 alvherre 473 ECB : {
474 : char tzname[TZ_STRLEN_MAX + 1];
475 : int dterr;
476 : int tz;
477 :
3323 alvherre 478 GIC 93 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
3323 alvherre 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
3260 bruce 486 : * reject. To avoid having it accept input that would otherwise be seen
3323 alvherre 487 : * as invalid, it's enough to disallow having a digit in the first
488 : * position of our input string.
489 : */
3321 heikki.linnakangas 490 GIC 93 : if (isdigit((unsigned char) *tzname))
3323 alvherre 491 3 : ereport(ERROR,
492 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1722 andres 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 :
121 tgl 497 GNC 90 : dterr = DecodeTimezone(tzname, &tz);
498 90 : if (dterr != 0)
499 : {
3323 alvherre 500 ECB : int type,
501 : val;
502 : pg_tz *tzp;
503 :
121 tgl 504 GNC 36 : if (dterr == DTERR_TZDISP_OVERFLOW)
3323 alvherre 505 GIC 6 : ereport(ERROR,
506 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
507 : errmsg("numeric time zone \"%s\" out of range", tzname)));
121 tgl 508 GNC 30 : else if (dterr != DTERR_BAD_FORMAT)
3323 alvherre 509 UIC 0 : ereport(ERROR,
3323 alvherre 510 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
511 : errmsg("time zone \"%s\" not recognized", tzname)));
512 :
23 tgl 513 GNC 30 : type = DecodeTimezoneName(tzname, &val, &tzp);
3323 alvherre 514 ECB :
23 tgl 515 GNC 27 : if (type == TZNAME_FIXED_OFFSET)
516 : {
517 : /* fixed-offset abbreviation */
3097 tgl 518 GIC 6 : tz = -val;
3097 tgl 519 ECB : }
23 tgl 520 GNC 21 : else if (type == TZNAME_DYNTZ)
521 : {
522 : /* dynamic-offset abbreviation, resolve using specified time */
3097 tgl 523 CBC 6 : tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
524 : }
525 : else
526 : {
527 : /* full zone name */
23 tgl 528 GNC 15 : tz = DetermineTimeZoneOffset(tm, tzp);
529 : }
3323 alvherre 530 ECB : }
531 :
3323 alvherre 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 *
22 tgl 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
3323 alvherre 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;
922 tgl 562 105 : bool bc = false;
563 : Timestamp result;
564 :
3323 alvherre 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 */
922 tgl 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 :
3323 alvherre 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))
3323 alvherre 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 :
3323 alvherre 590 CBC 102 : date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
591 :
592 : /* Check for time overflow */
1039 tgl 593 102 : if (float_time_overflows(hour, min, sec))
3323 alvherre 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 */
3323 alvherre 600 CBC 102 : time = (((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
1039 tgl 601 102 : * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
602 :
3323 alvherre 603 102 : result = date * USECS_PER_DAY + time;
604 : /* check for major overflow */
605 102 : if ((result - time) / USECS_PER_DAY != date)
3323 alvherre 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 */
3323 alvherre 614 CBC 102 : if ((result < 0 && date > 0) ||
615 75 : (result > 0 && date < -1))
3323 alvherre 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 */
2580 tgl 623 CBC 102 : if (!IS_VALID_TIMESTAMP(result))
2580 tgl 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 :
3323 alvherre 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)
3323 alvherre 697 UBC 0 : ereport(ERROR,
698 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
699 : errmsg("timestamp out of range")));
700 :
3323 alvherre 701 CBC 93 : tz = parse_sane_timezone(&tt, zone);
702 :
2580 tgl 703 81 : result = dt2local(timestamp, -tz);
704 :
705 81 : if (!IS_VALID_TIMESTAMP(result))
2580 tgl 706 UBC 0 : ereport(ERROR,
707 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
708 : errmsg("timestamp out of range")));
709 :
2580 tgl 710 CBC 81 : PG_RETURN_TIMESTAMPTZ(result);
711 : }
712 :
713 : /*
714 : * to_timestamp(double precision)
715 : * Convert UNIX epoch to timestamptz.
716 : */
717 : Datum
2567 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)
2250 741 12 : || seconds >=
742 : (float8) SECS_PER_DAY * (TIMESTAMP_END_JULIAN - UNIX_EPOCH_JDATE))
2567 tgl 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 */
2567 tgl 748 CBC 12 : seconds -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
749 :
2250 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 */
2567 754 12 : if (!IS_VALID_TIMESTAMP(result))
2567 tgl 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 :
2567 tgl 761 CBC 18 : PG_RETURN_TIMESTAMP(result);
762 : }
763 :
764 : /* timestamptz_out()
765 : * Convert a timestamp to external form.
766 : */
767 : Datum
7863 lockhart 768 35021 : timestamptz_out(PG_FUNCTION_ARGS)
769 : {
7272 tgl 770 35021 : TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
771 : char *result;
772 : int tz;
773 : struct pg_tm tt,
9344 bruce 774 35021 : *tm = &tt;
775 : fsec_t fsec;
776 : const char *tzn;
777 : char buf[MAXDATELEN + 1];
778 :
7863 lockhart 779 35021 : if (TIMESTAMP_NOT_FINITE(dt))
8339 tgl 780 94 : EncodeSpecialTimestamp(dt, buf);
6507 bruce 781 34927 : else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
4043 peter_e 782 34927 : EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
783 : else
7196 tgl 784 UBC 0 : ereport(ERROR,
785 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
786 : errmsg("timestamp out of range")));
787 :
8339 tgl 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
7272 tgl 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
6482 803 0 : int32 typmod = PG_GETARG_INT32(2);
804 : TimestampTz timestamp;
805 : int tz;
806 : struct pg_tm tt,
6884 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 */ ;
2580 815 0 : else if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0 ||
816 0 : !IS_VALID_TIMESTAMP(timestamp))
6884 817 0 : ereport(ERROR,
818 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
819 : errmsg("timestamp out of range")));
820 :
121 tgl 821 UNC 0 : AdjustTimestampForTypmod(×tamp, typmod, NULL);
822 :
6884 tgl 823 UBC 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
824 : }
825 :
826 : /*
827 : * timestamptz_send - converts timestamptz to binary format
828 : */
829 : Datum
7272 830 0 : timestamptz_send(PG_FUNCTION_ARGS)
831 : {
7188 bruce 832 0 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
833 : StringInfoData buf;
834 :
7272 tgl 835 0 : pq_begintypsend(&buf);
836 0 : pq_sendint64(&buf, timestamp);
837 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
838 : }
839 :
840 : Datum
5944 tgl 841 CBC 314 : timestamptztypmodin(PG_FUNCTION_ARGS)
842 : {
5624 bruce 843 314 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
844 :
5944 tgl 845 314 : PG_RETURN_INT32(anytimestamp_typmodin(true, ta));
846 : }
847 :
848 : Datum
849 5 : timestamptztypmodout(PG_FUNCTION_ARGS)
850 : {
5624 bruce 851 5 : int32 typmod = PG_GETARG_INT32(0);
852 :
5944 tgl 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
7858 lockhart 862 228 : timestamptz_scale(PG_FUNCTION_ARGS)
863 : {
7272 tgl 864 228 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
7858 lockhart 865 228 : int32 typmod = PG_GETARG_INT32(1);
866 : TimestampTz result;
867 :
868 228 : result = timestamp;
869 :
121 tgl 870 GNC 228 : AdjustTimestampForTypmod(&result, typmod, NULL);
871 :
7858 lockhart 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
8339 tgl 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);
7843 lockhart 888 ECB : #endif
7843 lockhart 889 CBC 4653 : int32 typmod = PG_GETARG_INT32(2);
121 tgl 890 GNC 4653 : Node *escontext = fcinfo->context;
891 : Interval *result;
892 : struct pg_itm_in tt,
372 tgl 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 :
372 tgl 903 GIC 4653 : itm_in->tm_year = 0;
372 tgl 904 CBC 4653 : itm_in->tm_mon = 0;
905 4653 : itm_in->tm_mday = 0;
906 4653 : itm_in->tm_usec = 0;
8453 lockhart 907 ECB :
5324 tgl 908 GIC 4653 : if (typmod >= 0)
5324 tgl 909 CBC 162 : range = INTERVAL_RANGE(typmod);
5324 tgl 910 ECB : else
5324 tgl 911 GIC 4491 : range = INTERVAL_FULL_RANGE;
5324 tgl 912 ECB :
6527 neilc 913 GIC 4653 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf), field,
6527 neilc 914 ECB : ftype, MAXDATEFIELDS, &nf);
7165 tgl 915 GIC 4653 : if (dterr == 0)
5262 tgl 916 CBC 4653 : dterr = DecodeInterval(field, ftype, nf, range,
372 tgl 917 ECB : &dtype, itm_in);
918 :
919 : /* if those functions think it's a bad format, try ISO8601 style */
5262 tgl 920 GIC 4653 : if (dterr == DTERR_BAD_FORMAT)
5050 bruce 921 CBC 267 : dterr = DecodeISO8601Interval(str,
372 tgl 922 ECB : &dtype, itm_in);
923 :
7165 tgl 924 GIC 4653 : if (dterr != 0)
7165 tgl 925 ECB : {
7165 tgl 926 GIC 438 : if (dterr == DTERR_FIELD_OVERFLOW)
7165 tgl 927 CBC 360 : dterr = DTERR_INTERVAL_OVERFLOW;
121 tgl 928 GNC 438 : DateTimeParseError(dterr, &extra, str, "interval", escontext);
929 12 : PG_RETURN_NULL();
7165 tgl 930 ECB : }
8453 lockhart 931 :
7863 lockhart 932 GIC 4215 : result = (Interval *) palloc(sizeof(Interval));
933 :
8453 lockhart 934 CBC 4215 : switch (dtype)
935 : {
936 4215 : case DTK_DELTA:
372 tgl 937 GIC 4215 : if (itmin2interval(itm_in, result) != 0)
121 tgl 938 GNC 9 : ereturn(escontext, (Datum) 0,
7196 tgl 939 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
940 : errmsg("interval out of range")));
7863 lockhart 941 GIC 4206 : break;
942 :
9313 lockhart 943 LBC 0 : default:
7196 tgl 944 UIC 0 : elog(ERROR, "unexpected dtype %d while parsing interval \"%s\"",
7196 tgl 945 EUB : dtype, str);
9313 lockhart 946 : }
947 :
121 tgl 948 GNC 4206 : AdjustIntervalForTypmod(result, typmod, escontext);
949 :
7863 lockhart 950 CBC 4206 : PG_RETURN_INTERVAL_P(result);
951 : }
8453 lockhart 952 ECB :
953 : /* interval_out()
954 : * Convert a time span to external form.
955 : */
956 : Datum
8339 tgl 957 GIC 6316 : interval_out(PG_FUNCTION_ARGS)
958 : {
8339 tgl 959 CBC 6316 : Interval *span = PG_GETARG_INTERVAL_P(0);
960 : char *result;
372 tgl 961 ECB : struct pg_itm tt,
372 tgl 962 GIC 6316 : *itm = &tt;
963 : char buf[MAXDATELEN + 1];
8453 lockhart 964 ECB :
372 tgl 965 GIC 6316 : interval2itm(*span, itm);
966 6316 : EncodeInterval(itm, IntervalStyle, buf);
8453 lockhart 967 ECB :
8339 tgl 968 CBC 6316 : result = pstrdup(buf);
8339 tgl 969 GIC 6316 : PG_RETURN_CSTRING(result);
8339 tgl 970 ECB : }
8453 lockhart 971 :
972 : /*
973 : * interval_recv - converts external binary format to interval
974 : */
975 : Datum
7272 tgl 976 UIC 0 : interval_recv(PG_FUNCTION_ARGS)
977 : {
7272 tgl 978 UBC 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
979 :
6482 tgl 980 EUB : #ifdef NOT_USED
981 : Oid typelem = PG_GETARG_OID(1);
982 : #endif
6482 tgl 983 UIC 0 : int32 typmod = PG_GETARG_INT32(2);
984 : Interval *interval;
7272 tgl 985 EUB :
7272 tgl 986 UIC 0 : interval = (Interval *) palloc(sizeof(Interval));
987 :
6530 bruce 988 UBC 0 : interval->time = pq_getmsgint64(buf);
6472 bruce 989 UIC 0 : interval->day = pq_getmsgint(buf, sizeof(interval->day));
6530 bruce 990 UBC 0 : interval->month = pq_getmsgint(buf, sizeof(interval->month));
7272 tgl 991 EUB :
121 tgl 992 UNC 0 : AdjustIntervalForTypmod(interval, typmod, NULL);
993 :
7272 tgl 994 UBC 0 : PG_RETURN_INTERVAL_P(interval);
995 : }
7272 tgl 996 EUB :
997 : /*
998 : * interval_send - converts interval to binary format
999 : */
1000 : Datum
7272 tgl 1001 UIC 0 : interval_send(PG_FUNCTION_ARGS)
1002 : {
7272 tgl 1003 UBC 0 : Interval *interval = PG_GETARG_INTERVAL_P(0);
1004 : StringInfoData buf;
7272 tgl 1005 EUB :
7272 tgl 1006 UIC 0 : pq_begintypsend(&buf);
1007 0 : pq_sendint64(&buf, interval->time);
2006 andres 1008 UBC 0 : pq_sendint32(&buf, interval->day);
1009 0 : pq_sendint32(&buf, interval->month);
7272 tgl 1010 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
7272 tgl 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
5944 tgl 1026 GIC 171 : intervaltypmodin(PG_FUNCTION_ARGS)
1027 : {
5624 bruce 1028 CBC 171 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1029 : int32 *tl;
5624 bruce 1030 ECB : int n;
1031 : int32 typmod;
1032 :
5777 tgl 1033 GIC 171 : tl = ArrayGetIntegerTypmods(ta, &n);
1034 :
5944 tgl 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 : */
5944 tgl 1041 GIC 171 : if (n > 0)
1042 : {
5944 tgl 1043 CBC 171 : switch (tl[0])
1044 : {
1045 171 : case INTERVAL_MASK(YEAR):
1046 : case INTERVAL_MASK(MONTH):
5944 tgl 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 */
5944 tgl 1060 GIC 171 : break;
5944 tgl 1061 UIC 0 : default:
5944 tgl 1062 LBC 0 : ereport(ERROR,
5944 tgl 1063 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1064 : errmsg("invalid INTERVAL type modifier")));
1065 : }
1066 : }
1067 :
5944 tgl 1068 GIC 171 : if (n == 1)
1069 : {
5944 tgl 1070 CBC 129 : if (tl[0] != INTERVAL_FULL_RANGE)
5944 tgl 1071 GIC 129 : typmod = INTERVAL_TYPMOD(INTERVAL_FULL_PRECISION, tl[0]);
5944 tgl 1072 ECB : else
5944 tgl 1073 LBC 0 : typmod = -1;
1074 : }
5944 tgl 1075 GBC 42 : else if (n == 2)
1076 : {
5944 tgl 1077 CBC 42 : if (tl[1] < 0)
5944 tgl 1078 UIC 0 : ereport(ERROR,
5944 tgl 1079 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5944 tgl 1080 EUB : errmsg("INTERVAL(%d) precision must not be negative",
1081 : tl[1])));
5944 tgl 1082 GIC 42 : if (tl[1] > MAX_INTERVAL_PRECISION)
1083 : {
5944 tgl 1084 LBC 0 : ereport(WARNING,
1085 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2118 tgl 1086 EUB : errmsg("INTERVAL(%d) precision reduced to maximum allowed, %d",
1087 : tl[1], MAX_INTERVAL_PRECISION)));
5944 tgl 1088 UIC 0 : typmod = INTERVAL_TYPMOD(MAX_INTERVAL_PRECISION, tl[0]);
1089 : }
5944 tgl 1090 EUB : else
5944 tgl 1091 GIC 42 : typmod = INTERVAL_TYPMOD(tl[1], tl[0]);
1092 : }
5944 tgl 1093 ECB : else
1094 : {
5944 tgl 1095 UIC 0 : ereport(ERROR,
1096 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5624 bruce 1097 EUB : errmsg("invalid INTERVAL type modifier")));
1098 : typmod = 0; /* keep compiler quiet */
1099 : }
1100 :
5944 tgl 1101 GIC 171 : PG_RETURN_INT32(typmod);
1102 : }
5944 tgl 1103 ECB :
1104 : Datum
5944 tgl 1105 UIC 0 : intervaltypmodout(PG_FUNCTION_ARGS)
1106 : {
5624 bruce 1107 UBC 0 : int32 typmod = PG_GETARG_INT32(0);
5944 tgl 1108 UIC 0 : char *res = (char *) palloc(64);
5624 bruce 1109 EUB : int fields;
1110 : int precision;
1111 : const char *fieldstr;
1112 :
5944 tgl 1113 UIC 0 : if (typmod < 0)
1114 : {
5944 tgl 1115 UBC 0 : *res = '\0';
5944 tgl 1116 UIC 0 : PG_RETURN_CSTRING(res);
5944 tgl 1117 EUB : }
1118 :
5944 tgl 1119 UIC 0 : fields = INTERVAL_RANGE(typmod);
1120 0 : precision = INTERVAL_PRECISION(typmod);
5944 tgl 1121 EUB :
5944 tgl 1122 UBC 0 : switch (fields)
1123 : {
1124 0 : case INTERVAL_MASK(YEAR):
5944 tgl 1125 UIC 0 : fieldstr = " year";
5944 tgl 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);
5944 tgl 1168 EUB : fieldstr = "";
1169 : break;
1170 : }
1171 :
5944 tgl 1172 UIC 0 : if (precision != INTERVAL_FULL_PRECISION)
5323 1173 0 : snprintf(res, 64, "%s(%d)", fieldstr, precision);
5944 tgl 1174 EUB : else
5944 tgl 1175 UBC 0 : snprintf(res, 64, "%s", fieldstr);
1176 :
1177 0 : PG_RETURN_CSTRING(res);
1178 : }
5944 tgl 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
2294 tgl 1191 GIC 18 : intervaltypmodleastfield(int32 typmod)
1192 : {
2294 tgl 1193 CBC 18 : if (typmod < 0)
2294 tgl 1194 GIC 6 : return 0; /* SECOND */
2294 tgl 1195 ECB :
2294 tgl 1196 CBC 12 : switch (INTERVAL_RANGE(typmod))
1197 : {
1198 3 : case INTERVAL_MASK(YEAR):
2294 tgl 1199 GIC 3 : return 5; /* YEAR */
2294 tgl 1200 CBC 6 : case INTERVAL_MASK(MONTH):
1201 6 : return 4; /* MONTH */
2294 tgl 1202 LBC 0 : case INTERVAL_MASK(DAY):
1203 0 : return 3; /* DAY */
2294 tgl 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 */
2294 tgl 1214 GBC 3 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
1215 3 : return 1; /* MINUTE */
2294 tgl 1216 LBC 0 : case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
1217 0 : return 0; /* SECOND */
2294 tgl 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);
2294 tgl 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
1520 tgl 1244 GIC 18 : interval_support(PG_FUNCTION_ARGS)
1245 : {
1520 tgl 1246 CBC 18 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
4078 rhaas 1247 GIC 18 : Node *ret = NULL;
4078 rhaas 1248 ECB :
1520 tgl 1249 CBC 18 : if (IsA(rawreq, SupportRequestSimplify))
1250 : {
1251 9 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1520 tgl 1252 GIC 9 : FuncExpr *expr = req->fcall;
1520 tgl 1253 ECB : Node *typmod;
4078 rhaas 1254 :
1520 tgl 1255 GIC 9 : Assert(list_length(expr->args) >= 2);
1256 :
1520 tgl 1257 CBC 9 : typmod = (Node *) lsecond(expr->args);
1258 :
1058 1259 9 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
1260 : {
1520 1261 9 : Node *source = (Node *) linitial(expr->args);
1520 tgl 1262 GIC 9 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
1520 tgl 1263 ECB : bool noop;
1264 :
1520 tgl 1265 GIC 9 : if (new_typmod < 0)
1520 tgl 1266 UIC 0 : noop = true;
2294 tgl 1267 ECB : else
1520 tgl 1268 EUB : {
1520 tgl 1269 GIC 9 : int32 old_typmod = exprTypmod(source);
1270 : int old_least_field;
1520 tgl 1271 ECB : int new_least_field;
1272 : int old_precis;
1273 : int new_precis;
1274 :
1520 tgl 1275 GIC 9 : old_least_field = intervaltypmodleastfield(old_typmod);
1276 9 : new_least_field = intervaltypmodleastfield(new_typmod);
1520 tgl 1277 CBC 9 : if (old_typmod < 0)
1278 6 : old_precis = INTERVAL_FULL_PRECISION;
1520 tgl 1279 ECB : else
1520 tgl 1280 CBC 3 : old_precis = INTERVAL_PRECISION(old_typmod);
1520 tgl 1281 GIC 9 : new_precis = INTERVAL_PRECISION(new_typmod);
1520 tgl 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 : */
1520 tgl 1289 GIC 9 : noop = (new_least_field <= old_least_field) &&
1520 tgl 1290 UIC 0 : (old_least_field > 0 /* SECOND */ ||
1520 tgl 1291 LBC 0 : new_precis >= MAX_INTERVAL_PRECISION ||
1520 tgl 1292 EUB : new_precis >= old_precis);
1293 : }
1520 tgl 1294 GIC 9 : if (noop)
1520 tgl 1295 UIC 0 : ret = relabel_to_typmod(source, new_typmod);
4078 rhaas 1296 ECB : }
4078 rhaas 1297 EUB : }
1298 :
4078 rhaas 1299 GIC 18 : PG_RETURN_POINTER(ret);
1300 : }
4078 rhaas 1301 ECB :
1302 : /* interval_scale()
1303 : * Adjust interval type for specified fields.
1304 : * Used by PostgreSQL type system to stuff columns.
1305 : */
1306 : Datum
7843 lockhart 1307 GIC 90 : interval_scale(PG_FUNCTION_ARGS)
1308 : {
7843 lockhart 1309 CBC 90 : Interval *interval = PG_GETARG_INTERVAL_P(0);
7843 lockhart 1310 GIC 90 : int32 typmod = PG_GETARG_INT32(1);
7843 lockhart 1311 ECB : Interval *result;
1312 :
7843 lockhart 1313 GIC 90 : result = palloc(sizeof(Interval));
1314 90 : *result = *interval;
7843 lockhart 1315 ECB :
121 tgl 1316 GNC 90 : AdjustIntervalForTypmod(result, typmod, NULL);
1317 :
7843 lockhart 1318 CBC 90 : PG_RETURN_INTERVAL_P(result);
1319 : }
6385 bruce 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
121 tgl 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),
7658 lockhart 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 : */
5324 tgl 1356 GIC 4296 : if (typmod >= 0)
1357 : {
7553 lockhart 1358 225 : int range = INTERVAL_RANGE(typmod);
1359 225 : int precision = INTERVAL_PRECISION(typmod);
1360 :
1361 : /*
5050 bruce 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 : */
7553 lockhart 1381 GIC 225 : if (range == INTERVAL_FULL_RANGE)
1382 : {
1383 : /* Do nothing... */
1384 : }
1385 219 : else if (range == INTERVAL_MASK(YEAR))
1386 : {
6471 bruce 1387 CBC 33 : interval->month = (interval->month / MONTHS_PER_YEAR) * MONTHS_PER_YEAR;
6472 bruce 1388 GIC 33 : interval->day = 0;
6530 1389 33 : interval->time = 0;
1390 : }
7553 lockhart 1391 CBC 186 : else if (range == INTERVAL_MASK(MONTH))
1392 : {
6472 bruce 1393 36 : interval->day = 0;
6530 1394 36 : interval->time = 0;
7843 lockhart 1395 ECB : }
1396 : /* YEAR TO MONTH */
7553 lockhart 1397 CBC 150 : else if (range == (INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH)))
1398 : {
6472 bruce 1399 9 : interval->day = 0;
6530 1400 9 : interval->time = 0;
1401 : }
7553 lockhart 1402 GIC 141 : else if (range == INTERVAL_MASK(DAY))
7843 lockhart 1403 ECB : {
6472 bruce 1404 GIC 6 : interval->time = 0;
7843 lockhart 1405 ECB : }
7553 lockhart 1406 CBC 135 : else if (range == INTERVAL_MASK(HOUR))
1407 : {
6530 bruce 1408 6 : interval->time = (interval->time / USECS_PER_HOUR) *
1409 : USECS_PER_HOUR;
7843 lockhart 1410 ECB : }
7553 lockhart 1411 GIC 129 : else if (range == INTERVAL_MASK(MINUTE))
7843 lockhart 1412 ECB : {
6530 bruce 1413 GIC 6 : interval->time = (interval->time / USECS_PER_MINUTE) *
6385 bruce 1414 ECB : USECS_PER_MINUTE;
1415 : }
7553 lockhart 1416 GIC 123 : else if (range == INTERVAL_MASK(SECOND))
7843 lockhart 1417 ECB : {
1418 : /* fractional-second rounding will be dealt with below */
1419 : }
1420 : /* DAY TO HOUR */
7553 lockhart 1421 GIC 111 : else if (range == (INTERVAL_MASK(DAY) |
7553 lockhart 1422 ECB : INTERVAL_MASK(HOUR)))
1423 : {
6530 bruce 1424 GIC 12 : interval->time = (interval->time / USECS_PER_HOUR) *
1425 : USECS_PER_HOUR;
1426 : }
7843 lockhart 1427 ECB : /* DAY TO MINUTE */
7553 lockhart 1428 GIC 99 : else if (range == (INTERVAL_MASK(DAY) |
1429 : INTERVAL_MASK(HOUR) |
7553 lockhart 1430 ECB : INTERVAL_MASK(MINUTE)))
1431 : {
6530 bruce 1432 GIC 36 : interval->time = (interval->time / USECS_PER_MINUTE) *
1433 : USECS_PER_MINUTE;
7843 lockhart 1434 ECB : }
1435 : /* DAY TO SECOND */
7553 lockhart 1436 GIC 63 : else if (range == (INTERVAL_MASK(DAY) |
1437 : INTERVAL_MASK(HOUR) |
7553 lockhart 1438 ECB : INTERVAL_MASK(MINUTE) |
1439 : INTERVAL_MASK(SECOND)))
1440 : {
1441 : /* fractional-second rounding will be dealt with below */
5060 tgl 1442 : }
1443 : /* HOUR TO MINUTE */
7553 lockhart 1444 GIC 45 : else if (range == (INTERVAL_MASK(HOUR) |
1445 : INTERVAL_MASK(MINUTE)))
1446 : {
6530 bruce 1447 6 : interval->time = (interval->time / USECS_PER_MINUTE) *
1448 : USECS_PER_MINUTE;
1449 : }
7843 lockhart 1450 ECB : /* HOUR TO SECOND */
7553 lockhart 1451 GIC 39 : else if (range == (INTERVAL_MASK(HOUR) |
1452 : INTERVAL_MASK(MINUTE) |
7553 lockhart 1453 ECB : INTERVAL_MASK(SECOND)))
1454 : {
1455 : /* fractional-second rounding will be dealt with below */
1456 : }
7843 1457 : /* MINUTE TO SECOND */
7553 lockhart 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
7196 tgl 1464 LBC 0 : elog(ERROR, "unrecognized interval typmod: %d", typmod);
1465 :
1466 : /* Need to adjust sub-second precision? */
7553 lockhart 1467 GIC 225 : if (precision != INTERVAL_FULL_PRECISION)
1468 : {
6530 bruce 1469 33 : if (precision < 0 || precision > MAX_INTERVAL_PRECISION)
121 tgl 1470 UNC 0 : ereturn(escontext, false,
1471 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1472 : errmsg("interval(%d) precision must be between %d and %d",
2118 tgl 1473 ECB : precision, 0, MAX_INTERVAL_PRECISION)));
1474 :
7658 lockhart 1475 CBC 33 : if (interval->time >= INT64CONST(0))
7658 lockhart 1476 EUB : {
6529 bruce 1477 GIC 33 : interval->time = ((interval->time +
6385 1478 33 : IntervalOffsets[precision]) /
1479 33 : IntervalScales[precision]) *
1480 33 : IntervalScales[precision];
7658 lockhart 1481 ECB : }
1482 : else
1483 : {
6530 bruce 1484 LBC 0 : interval->time = -(((-interval->time +
6385 1485 0 : IntervalOffsets[precision]) /
6530 1486 0 : IntervalScales[precision]) *
6385 bruce 1487 UIC 0 : IntervalScales[precision]);
1488 : }
1489 : }
7843 lockhart 1490 EUB : }
1491 :
121 tgl 1492 GNC 4296 : return true;
7843 lockhart 1493 EUB : }
1494 :
3323 alvherre 1495 : /*
1496 : * make_interval - numeric Interval constructor
1497 : */
1498 : Datum
3323 alvherre 1499 GIC 27 : make_interval(PG_FUNCTION_ARGS)
3323 alvherre 1500 ECB : {
3323 alvherre 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);
3323 alvherre 1507 CBC 27 : double secs = PG_GETARG_FLOAT8(6);
1508 : Interval *result;
3323 alvherre 1509 ECB :
3322 tgl 1510 : /*
3260 bruce 1511 : * Reject out-of-range inputs. We really ought to check the integer
3322 tgl 1512 : * inputs as well, but it's not entirely clear what limits to apply.
1513 : */
3322 tgl 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 :
3323 alvherre 1519 GIC 21 : result = (Interval *) palloc(sizeof(Interval));
1520 21 : result->month = years * MONTHS_PER_YEAR + months;
1521 21 : result->day = weeks * 7 + days;
3323 alvherre 1522 ECB :
2250 tgl 1523 CBC 21 : secs = rint(secs * USECS_PER_SEC);
2251 tgl 1524 GIC 21 : result->time = hours * ((int64) SECS_PER_HOUR * USECS_PER_SEC) +
1525 21 : mins * ((int64) SECS_PER_MINUTE * USECS_PER_SEC) +
2250 1526 21 : (int64) secs;
3323 alvherre 1527 ECB :
3323 alvherre 1528 CBC 21 : PG_RETURN_INTERVAL_P(result);
3323 alvherre 1529 ECB : }
1530 :
8453 lockhart 1531 : /* EncodeSpecialTimestamp()
1532 : * Convert reserved timestamp data type to string.
1533 : */
2728 tgl 1534 : void
8453 lockhart 1535 GIC 228 : EncodeSpecialTimestamp(Timestamp dt, char *str)
8453 lockhart 1536 ECB : {
7863 lockhart 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 */
5290 tgl 1542 UIC 0 : elog(ERROR, "invalid argument for EncodeSpecialTimestamp");
5290 tgl 1543 CBC 228 : }
1544 :
8339 tgl 1545 ECB : Datum
8339 tgl 1546 CBC 35250 : now(PG_FUNCTION_ARGS)
9522 scrappy 1547 ECB : {
6493 tgl 1548 CBC 35250 : PG_RETURN_TIMESTAMPTZ(GetCurrentTransactionStartTimestamp());
1549 : }
9522 scrappy 1550 EUB :
6193 bruce 1551 ECB : Datum
6193 bruce 1552 GIC 3 : statement_timestamp(PG_FUNCTION_ARGS)
1553 : {
6193 bruce 1554 CBC 3 : PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp());
1555 : }
6193 bruce 1556 ECB :
1557 : Datum
6193 bruce 1558 GIC 9 : clock_timestamp(PG_FUNCTION_ARGS)
1559 : {
6193 bruce 1560 CBC 9 : PG_RETURN_TIMESTAMPTZ(GetCurrentTimestamp());
1561 : }
6193 bruce 1562 ECB :
1563 : Datum
5453 tgl 1564 UIC 0 : pg_postmaster_start_time(PG_FUNCTION_ARGS)
1565 : {
6493 tgl 1566 LBC 0 : PG_RETURN_TIMESTAMPTZ(PgStartTime);
1567 : }
5453 tgl 1568 ECB :
1569 : Datum
5453 tgl 1570 UIC 0 : pg_conf_load_time(PG_FUNCTION_ARGS)
1571 : {
5453 tgl 1572 UBC 0 : PG_RETURN_TIMESTAMPTZ(PgReloadTime);
1573 : }
6493 tgl 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
6493 tgl 1582 GIC 4222874 : GetCurrentTimestamp(void)
1583 : {
1584 : TimestampTz result;
1585 : struct timeval tp;
1586 :
1587 4222874 : gettimeofday(&tp, NULL);
1588 :
6449 1589 4222874 : result = (TimestampTz) tp.tv_sec -
6493 tgl 1590 ECB : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
3805 heikki.linnakangas 1591 GIC 4222874 : result = (result * USECS_PER_SEC) + tp.tv_usec;
1592 :
1593 4222874 : return result;
1594 : }
3805 heikki.linnakangas 1595 ECB :
1596 : /*
1597 : * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
1598 : */
1599 : Datum
139 michael 1600 GNC 139 : current_timestamp(PG_FUNCTION_ARGS)
2427 tgl 1601 ECB : {
1602 : TimestampTz ts;
139 michael 1603 GNC 139 : int32 typmod = -1;
1604 :
1605 139 : if (!PG_ARGISNULL(0))
100 1606 6 : typmod = anytimestamp_typmod_check(true, PG_GETARG_INT32(0));
1607 :
2427 tgl 1608 GIC 139 : ts = GetCurrentTransactionStartTimestamp();
1609 139 : if (typmod >= 0)
121 tgl 1610 GNC 6 : AdjustTimestampForTypmod(&ts, typmod, NULL);
139 michael 1611 139 : return TimestampTzGetDatum(ts);
2427 tgl 1612 ECB : }
1613 :
1614 : /*
1615 : * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
1616 : */
1617 : Datum
139 michael 1618 GNC 33 : sql_localtimestamp(PG_FUNCTION_ARGS)
1619 : {
2427 tgl 1620 ECB : Timestamp ts;
139 michael 1621 GNC 33 : int32 typmod = -1;
1622 :
1623 33 : if (!PG_ARGISNULL(0))
100 1624 3 : typmod = anytimestamp_typmod_check(false, PG_GETARG_INT32(0));
2427 tgl 1625 ECB :
2427 tgl 1626 CBC 33 : ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
1627 33 : if (typmod >= 0)
121 tgl 1628 GNC 3 : AdjustTimestampForTypmod(&ts, typmod, NULL);
139 michael 1629 33 : return TimestampGetDatum(ts);
1630 : }
1631 :
1632 :
1633 : /*
1634 : * timeofday(*) -- returns the current time as a text.
1641 andres 1635 ECB : */
1636 : Datum
1641 andres 1637 GIC 400 : timeofday(PG_FUNCTION_ARGS)
1641 andres 1638 ECB : {
1639 : struct timeval tp;
1640 : char templ[128];
1641 : char buf[128];
1642 : pg_time_t tt;
1643 :
1641 andres 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",
1641 andres 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 : /*
6137 tgl 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 : *
880 1663 : * We expect start_time <= stop_time. If not, we return zeros,
1664 : * since then we're already past the previously determined stop_time.
6137 1665 : */
1666 : void
6137 tgl 1667 CBC 583953 : TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
1668 : long *secs, int *microsecs)
1669 : {
6137 tgl 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 :
880 tgl 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
880 tgl 1703 GIC 138205 : TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
1704 : {
1705 : TimestampTz diff;
1706 :
1707 : /* Deal with zero or negative elapsed time quickly. */
73 tgl 1708 GNC 138205 : if (start_time >= stop_time)
880 tgl 1709 UIC 0 : return 0;
1710 : /* To not fail with timestamp infinities, we must detect overflow. */
73 tgl 1711 GNC 138205 : if (pg_sub_s64_overflow(stop_time, start_time, &diff))
73 tgl 1712 UNC 0 : return (long) INT_MAX;
73 tgl 1713 GNC 138205 : if (diff >= (INT_MAX * INT64CONST(1000) - 999))
73 tgl 1714 UNC 0 : return (long) INT_MAX;
1715 : else
880 tgl 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()).
5823 tgl 1725 ECB : */
1726 : bool
5823 tgl 1727 GIC 802366 : TimestampDifferenceExceeds(TimestampTz start_time,
1728 : TimestampTz stop_time,
1729 : int msec)
5823 tgl 1730 ECB : {
5823 tgl 1731 GBC 802366 : TimestampTz diff = stop_time - start_time;
1732 :
5823 tgl 1733 CBC 802366 : return (diff >= msec * INT64CONST(1000));
5823 tgl 1734 EUB : }
5823 tgl 1735 ECB :
6449 tgl 1736 EUB : /*
1737 : * Convert a time_t to TimestampTz.
6449 tgl 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
5530 tgl 1748 GIC 21266 : time_t_to_timestamptz(pg_time_t tm)
6449 tgl 1749 ECB : {
1750 : TimestampTz result;
1751 :
6449 tgl 1752 GIC 21266 : result = (TimestampTz) tm -
6449 tgl 1753 ECB : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
6449 tgl 1754 GIC 21266 : result *= USECS_PER_SEC;
6449 tgl 1755 ECB :
6449 tgl 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
6137 tgl 1770 CBC 15129 : timestamptz_to_time_t(TimestampTz t)
1771 : {
1772 : pg_time_t result;
1773 :
5530 1774 15129 : result = (pg_time_t) (t / USECS_PER_SEC +
1775 : ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY));
6137 tgl 1776 ECB :
6137 tgl 1777 GIC 15129 : return result;
6137 tgl 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 *
5823 tgl 1790 GIC 3745 : timestamptz_to_str(TimestampTz t)
1791 : {
5624 bruce 1792 ECB : static char buf[MAXDATELEN + 1];
1793 : int tz;
1794 : struct pg_tm tt,
5823 tgl 1795 GIC 3745 : *tm = &tt;
5823 tgl 1796 ECB : fsec_t fsec;
1797 : const char *tzn;
1798 :
5823 tgl 1799 CBC 3745 : if (TIMESTAMP_NOT_FINITE(t))
5823 tgl 1800 UIC 0 : EncodeSpecialTimestamp(t, buf);
5823 tgl 1801 GIC 3745 : else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
4043 peter_e 1802 3745 : EncodeDateTime(tm, fsec, true, tz, tzn, USE_ISO_DATES, buf);
1803 : else
5823 tgl 1804 UIC 0 : strlcpy(buf, "(timestamp out of range)", sizeof(buf));
1805 :
5823 tgl 1806 GIC 3745 : return buf;
1807 : }
1808 :
1809 :
1810 : void
7658 lockhart 1811 129609 : dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
8453 lockhart 1812 ECB : {
1813 : TimeOffset time;
1814 :
8453 lockhart 1815 GIC 129609 : time = jd;
1816 :
6530 bruce 1817 CBC 129609 : *hour = time / USECS_PER_HOUR;
6530 bruce 1818 GIC 129609 : time -= (*hour) * USECS_PER_HOUR;
1819 129609 : *min = time / USECS_PER_MINUTE;
1820 129609 : time -= (*min) * USECS_PER_MINUTE;
6530 bruce 1821 CBC 129609 : *sec = time / USECS_PER_SEC;
6530 bruce 1822 GBC 129609 : *fsec = time - (*sec * USECS_PER_SEC);
2118 tgl 1823 CBC 129609 : } /* dt2time() */
8453 lockhart 1824 ECB :
1825 :
6884 tgl 1826 EUB : /*
1827 : * timestamp2tm() - Convert timestamp data type to POSIX time structure.
6884 tgl 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
8453 lockhart 1833 : * -1 on out of range
1834 : *
1835 : * If attimezone is NULL, the global timezone setting will be used.
1836 : */
1837 : int
2118 tgl 1838 GIC 129603 : timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
8453 lockhart 1839 ECB : {
6385 bruce 1840 : Timestamp date;
6884 tgl 1841 : Timestamp time;
1842 : pg_time_t utime;
8453 lockhart 1843 :
3446 tgl 1844 : /* Use session timezone if caller asks for default */
3446 tgl 1845 CBC 129603 : if (attimezone == NULL)
3446 tgl 1846 GIC 120585 : attimezone = session_timezone;
1847 :
6391 1848 129603 : time = dt;
6530 bruce 1849 129603 : TMODULO(time, date, USECS_PER_DAY);
1850 :
7658 lockhart 1851 129603 : if (time < INT64CONST(0))
1852 : {
6530 bruce 1853 50836 : time += USECS_PER_DAY;
1854 50836 : date -= 1;
1855 : }
1856 :
1857 : /* add offset to go from J2000 back to standard Julian date */
6391 tgl 1858 129603 : date += POSTGRES_EPOCH_JDATE;
1859 :
6391 tgl 1860 ECB : /* Julian day routine does not work for negative Julian days */
6391 tgl 1861 GIC 129603 : if (date < 0 || date > (Timestamp) INT_MAX)
6391 tgl 1862 UIC 0 : return -1;
1863 :
6391 tgl 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 :
6884 tgl 1867 ECB : /* Done if no TZ conversion wanted */
6884 tgl 1868 CBC 129603 : if (tzp == NULL)
1869 : {
1870 41895 : tm->tm_isdst = -1;
1871 41895 : tm->tm_gmtoff = 0;
6884 tgl 1872 GIC 41895 : tm->tm_zone = NULL;
6884 tgl 1873 CBC 41895 : if (tzn != NULL)
6884 tgl 1874 UIC 0 : *tzn = NULL;
6884 tgl 1875 CBC 41895 : return 0;
6884 tgl 1876 ECB : }
1877 :
1878 : /*
1879 : * If the time falls within the range of pg_time_t, use pg_localtime() to
6385 bruce 1880 : * rotate to the local time zone.
1881 : *
1882 : * First, convert to an integral timestamp, avoiding possibly
6884 tgl 1883 : * platform-specific roundoff-in-wrong-direction errors, and adjust to
3260 bruce 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,
6385 bruce 1886 ECB : * so it should behave sanely on machines without int64.
6884 tgl 1887 : */
6530 bruce 1888 GIC 87708 : dt = (dt - *fsec) / USECS_PER_SEC +
1889 : (POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
6884 tgl 1890 CBC 87708 : utime = (pg_time_t) dt;
6884 tgl 1891 GIC 87708 : if ((Timestamp) utime == dt)
6884 tgl 1892 ECB : {
3446 tgl 1893 CBC 87708 : struct pg_tm *tx = pg_localtime(&utime, attimezone);
6884 tgl 1894 ECB :
6884 tgl 1895 CBC 87708 : tm->tm_year = tx->tm_year + 1900;
6884 tgl 1896 GBC 87708 : tm->tm_mon = tx->tm_mon + 1;
6884 tgl 1897 CBC 87708 : tm->tm_mday = tx->tm_mday;
6884 tgl 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;
6470 bruce 1904 87708 : *tzp = -tm->tm_gmtoff;
6884 tgl 1905 87708 : if (tzn != NULL)
4042 peter_e 1906 45769 : *tzn = tm->tm_zone;
1907 : }
1908 : else
1909 : {
6884 tgl 1910 ECB : /*
1911 : * When out of range of pg_time_t, treat as GMT
1912 : */
6884 tgl 1913 LBC 0 : *tzp = 0;
1914 : /* Mark this as *no* time zone available */
7841 lockhart 1915 0 : tm->tm_isdst = -1;
6884 tgl 1916 UIC 0 : tm->tm_gmtoff = 0;
6884 tgl 1917 LBC 0 : tm->tm_zone = NULL;
8453 lockhart 1918 0 : if (tzn != NULL)
1919 0 : *tzn = NULL;
8453 lockhart 1920 ECB : }
1921 :
8453 lockhart 1922 CBC 87708 : return 0;
7196 tgl 1923 ECB : }
8453 lockhart 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
2118 tgl 1934 GIC 82868 : tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
8453 lockhart 1935 EUB : {
1936 : TimeOffset date;
5497 tgl 1937 : TimeOffset time;
8453 lockhart 1938 :
2580 tgl 1939 : /* Prevent overflow in Julian-day routines */
8453 lockhart 1940 GBC 82868 : if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
5993 tgl 1941 EUB : {
5993 tgl 1942 GIC 6 : *result = 0; /* keep compiler quiet */
8453 lockhart 1943 6 : return -1;
5993 tgl 1944 ECB : }
1945 :
7310 tgl 1946 GIC 82862 : date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
7658 lockhart 1947 82862 : time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
1948 :
6530 bruce 1949 82862 : *result = date * USECS_PER_DAY + time;
1950 : /* check for major overflow */
1951 82862 : if ((*result - time) / USECS_PER_DAY != date)
1952 : {
5993 tgl 1953 3 : *result = 0; /* keep compiler quiet */
7219 1954 3 : return -1;
1955 : }
7219 tgl 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 */
3688 tgl 1958 GIC 82859 : if ((*result < 0 && date > 0) ||
1959 82859 : (*result > 0 && date < -1))
1960 : {
5993 tgl 1961 UIC 0 : *result = 0; /* keep compiler quiet */
7219 tgl 1962 LBC 0 : return -1;
1963 : }
8453 lockhart 1964 CBC 82859 : if (tzp != NULL)
1965 25119 : *result = dt2local(*result, -(*tzp));
1966 :
1967 : /* final range check catches just-out-of-range timestamps */
2580 tgl 1968 82859 : if (!IS_VALID_TIMESTAMP(*result))
2580 tgl 1969 ECB : {
2580 tgl 1970 GIC 12 : *result = 0; /* keep compiler quiet */
2580 tgl 1971 CBC 12 : return -1;
1972 : }
2580 tgl 1973 ECB :
8453 lockhart 1974 GIC 82847 : return 0;
7196 tgl 1975 ECB : }
8453 lockhart 1976 :
1977 :
1978 : /* interval2itm()
1979 : * Convert an Interval to a pg_itm structure.
372 tgl 1980 : * Note: overflow is not possible, because the pg_itm fields are
1981 : * wide enough for all possible conversion results.
1982 : */
372 tgl 1983 EUB : void
372 tgl 1984 GBC 6956 : interval2itm(Interval span, struct pg_itm *itm)
1985 : {
5497 tgl 1986 ECB : TimeOffset time;
1987 : TimeOffset tfrac;
1988 :
372 tgl 1989 GIC 6956 : itm->tm_year = span.month / MONTHS_PER_YEAR;
372 tgl 1990 CBC 6956 : itm->tm_mon = span.month % MONTHS_PER_YEAR;
372 tgl 1991 GIC 6956 : itm->tm_mday = span.day;
8453 lockhart 1992 CBC 6956 : time = span.time;
8453 lockhart 1993 ECB :
6375 tgl 1994 GIC 6956 : tfrac = time / USECS_PER_HOUR;
1995 6956 : time -= tfrac * USECS_PER_HOUR;
372 tgl 1996 CBC 6956 : itm->tm_hour = tfrac;
6375 tgl 1997 GIC 6956 : tfrac = time / USECS_PER_MINUTE;
1998 6956 : time -= tfrac * USECS_PER_MINUTE;
372 1999 6956 : itm->tm_min = (int) tfrac;
6375 2000 6956 : tfrac = time / USECS_PER_SEC;
372 2001 6956 : time -= tfrac * USECS_PER_SEC;
2002 6956 : itm->tm_sec = (int) tfrac;
2003 6956 : itm->tm_usec = (int) time;
2004 6956 : }
2005 :
372 tgl 2006 ECB : /* itm2interval()
2007 : * Convert a pg_itm structure to an Interval.
2008 : * Returns 0 if OK, -1 on overflow.
2009 : */
2010 : int
372 tgl 2011 LBC 0 : itm2interval(struct pg_itm *itm, Interval *span)
372 tgl 2012 ECB : {
372 tgl 2013 LBC 0 : int64 total_months = (int64) itm->tm_year * MONTHS_PER_YEAR + itm->tm_mon;
8453 lockhart 2014 ECB :
372 tgl 2015 UIC 0 : if (total_months > INT_MAX || total_months < INT_MIN)
372 tgl 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;
372 tgl 2022 ECB : /* tm_min, tm_sec are 32 bits, so intermediate products can't overflow */
372 tgl 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,
372 tgl 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;
8453 lockhart 2032 0 : return 0;
7196 tgl 2033 EUB : }
2034 :
372 2035 : /* itmin2interval()
2036 : * Convert a pg_itm_in structure to an Interval.
2037 : * Returns 0 if OK, -1 on overflow.
2038 : */
7885 bruce 2039 : int
372 tgl 2040 GBC 10761 : itmin2interval(struct pg_itm_in *itm_in, Interval *span)
8453 lockhart 2041 EUB : {
372 tgl 2042 GBC 10761 : int64 total_months = (int64) itm_in->tm_year * MONTHS_PER_YEAR + itm_in->tm_mon;
3356 bruce 2043 EUB :
3356 bruce 2044 GIC 10761 : if (total_months > INT_MAX || total_months < INT_MIN)
3356 bruce 2045 GBC 9 : return -1;
372 tgl 2046 10752 : span->month = (int32) total_months;
2047 10752 : span->day = itm_in->tm_mday;
2048 10752 : span->time = itm_in->tm_usec;
8453 lockhart 2049 10752 : return 0;
7196 tgl 2050 EUB : }
8453 lockhart 2051 :
5497 tgl 2052 : static TimeOffset
7658 lockhart 2053 GBC 82862 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
7658 lockhart 2054 EUB : {
6471 bruce 2055 GIC 82862 : return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
2056 : }
2057 :
2058 : static Timestamp
201 pg 2059 GNC 33246 : dt2local(Timestamp dt, int timezone)
2060 : {
2061 33246 : dt -= (timezone * USECS_PER_SEC);
8453 lockhart 2062 CBC 33246 : return dt;
2063 : }
8453 lockhart 2064 ECB :
2065 :
2066 : /*****************************************************************************
2067 : * PUBLIC ROUTINES *
2068 : *****************************************************************************/
2069 :
2070 :
8339 tgl 2071 : Datum
8339 tgl 2072 GIC 48 : timestamp_finite(PG_FUNCTION_ARGS)
2073 : {
6385 bruce 2074 48 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
8453 lockhart 2075 ECB :
8053 bruce 2076 GIC 48 : PG_RETURN_BOOL(!TIMESTAMP_NOT_FINITE(timestamp));
8339 tgl 2077 ECB : }
2078 :
2079 : Datum
8339 tgl 2080 UIC 0 : interval_finite(PG_FUNCTION_ARGS)
9522 scrappy 2081 ECB : {
7863 lockhart 2082 UIC 0 : PG_RETURN_BOOL(true);
8339 tgl 2083 ECB : }
8453 lockhart 2084 :
2085 :
2086 : /*----------------------------------------------------------
2087 : * Relational operators for timestamp.
2088 : *---------------------------------------------------------*/
2089 :
2090 : void
2118 tgl 2091 GIC 14186 : GetEpochTime(struct pg_tm *tm)
2092 : {
2093 : struct pg_tm *t0;
6797 bruce 2094 CBC 14186 : pg_time_t epoch = 0;
2095 :
6897 tgl 2096 14186 : t0 = pg_gmtime(&epoch);
2097 :
1636 2098 14186 : if (t0 == NULL)
1636 tgl 2099 UIC 0 : elog(ERROR, "could not convert epoch to timestamp: %m");
2100 :
8453 lockhart 2101 GIC 14186 : tm->tm_year = t0->tm_year;
8453 lockhart 2102 GBC 14186 : tm->tm_mon = t0->tm_mon;
8453 lockhart 2103 GIC 14186 : tm->tm_mday = t0->tm_mday;
8453 lockhart 2104 GBC 14186 : tm->tm_hour = t0->tm_hour;
8453 lockhart 2105 GIC 14186 : tm->tm_min = t0->tm_min;
2106 14186 : tm->tm_sec = t0->tm_sec;
2107 :
6884 tgl 2108 14186 : tm->tm_year += 1900;
8453 lockhart 2109 14186 : tm->tm_mon++;
6884 tgl 2110 14186 : }
2111 :
2112 : Timestamp
7863 lockhart 2113 CBC 14183 : SetEpochTimestamp(void)
2114 : {
2115 : Timestamp dt;
6797 bruce 2116 ECB : struct pg_tm tt,
7863 lockhart 2117 GIC 14183 : *tm = &tt;
8453 lockhart 2118 ECB :
7863 lockhart 2119 GIC 14183 : GetEpochTime(tm);
7196 tgl 2120 ECB : /* we don't bother to test for failure ... */
7863 lockhart 2121 GBC 14183 : tm2timestamp(tm, 0, NULL, &dt);
2122 :
8453 lockhart 2123 CBC 14183 : return dt;
2118 tgl 2124 ECB : } /* SetEpochTimestamp() */
8453 lockhart 2125 :
8339 tgl 2126 : /*
7184 2127 : * We are currently sharing some code between timestamp and timestamptz.
2128 : * The comparison functions are among them. - thomas 2001-09-25
2129 : *
8339 2130 : * timestamp_relop - is timestamp1 relop timestamp2
8453 lockhart 2131 : */
6994 tgl 2132 : int
8011 tgl 2133 GIC 300197 : timestamp_cmp_internal(Timestamp dt1, Timestamp dt2)
2134 : {
6529 bruce 2135 CBC 300197 : return (dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0);
2136 : }
2137 :
2138 : Datum
8339 tgl 2139 46214 : timestamp_eq(PG_FUNCTION_ARGS)
2140 : {
2141 46214 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
8339 tgl 2142 GIC 46214 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 2143 ECB :
8011 tgl 2144 GIC 46214 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) == 0);
8339 tgl 2145 ECB : }
2146 :
2147 : Datum
8339 tgl 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 :
8011 2153 393 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) != 0);
2154 : }
9522 scrappy 2155 ECB :
2156 : Datum
8339 tgl 2157 CBC 129215 : timestamp_lt(PG_FUNCTION_ARGS)
2158 : {
8339 tgl 2159 GIC 129215 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2160 129215 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 2161 ECB :
8011 tgl 2162 GIC 129215 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) < 0);
8339 tgl 2163 ECB : }
9522 scrappy 2164 :
2165 : Datum
8339 tgl 2166 CBC 49223 : timestamp_gt(PG_FUNCTION_ARGS)
2167 : {
8339 tgl 2168 GIC 49223 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2169 49223 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 2170 ECB :
8011 tgl 2171 GIC 49223 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) > 0);
8339 tgl 2172 ECB : }
8453 lockhart 2173 :
2174 : Datum
8339 tgl 2175 CBC 9253 : timestamp_le(PG_FUNCTION_ARGS)
2176 : {
8339 tgl 2177 GIC 9253 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2178 9253 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 2179 ECB :
8011 tgl 2180 GIC 9253 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) <= 0);
8339 tgl 2181 ECB : }
8453 lockhart 2182 :
2183 : Datum
8339 tgl 2184 CBC 9263 : timestamp_ge(PG_FUNCTION_ARGS)
2185 : {
8339 tgl 2186 GIC 9263 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2187 9263 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 2188 ECB :
8011 tgl 2189 GIC 9263 : PG_RETURN_BOOL(timestamp_cmp_internal(dt1, dt2) >= 0);
8339 tgl 2190 ECB : }
8453 lockhart 2191 :
2192 : Datum
8339 tgl 2193 CBC 17507 : timestamp_cmp(PG_FUNCTION_ARGS)
2194 : {
8339 tgl 2195 GIC 17507 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
2196 17507 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
9503 scrappy 2197 ECB :
8011 tgl 2198 GIC 17507 : PG_RETURN_INT32(timestamp_cmp_internal(dt1, dt2));
8339 tgl 2199 ECB : }
8453 lockhart 2200 :
2201 : #if SIZEOF_DATUM < 8
4141 tgl 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 : }
372 john.naylor 2211 : #endif
2212 :
2213 : Datum
4141 tgl 2214 GIC 459 : timestamp_sortsupport(PG_FUNCTION_ARGS)
4141 tgl 2215 ECB : {
3955 bruce 2216 GIC 459 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
4141 tgl 2217 ECB :
333 drowley 2218 : #if SIZEOF_DATUM >= 8
2219 :
372 john.naylor 2220 : /*
2221 : * If this build has pass-by-value timestamps, then we can use a standard
2222 : * comparator function.
2223 : */
372 john.naylor 2224 GIC 459 : ssup->comparator = ssup_datum_signed_cmp;
2225 : #else
2226 : ssup->comparator = timestamp_fastcmp;
2227 : #endif
4141 tgl 2228 459 : PG_RETURN_VOID();
2229 : }
2230 :
2231 : Datum
5756 2232 3243 : timestamp_hash(PG_FUNCTION_ARGS)
2233 : {
2234 3243 : return hashint8(fcinfo);
2235 : }
5756 tgl 2236 ECB :
2237 : Datum
2047 rhaas 2238 CBC 30 : timestamp_hash_extended(PG_FUNCTION_ARGS)
2239 : {
2047 rhaas 2240 GIC 30 : return hashint8extended(fcinfo);
2241 : }
2242 :
2243 : /*
2244 : * Cross-type comparison functions for timestamp vs timestamptz
2245 : */
6957 tgl 2246 ECB :
2247 : int32
914 tgl 2248 GIC 7899 : timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
2249 : {
914 tgl 2250 ECB : TimestampTz dt1;
2251 : int overflow;
2252 :
914 tgl 2253 GIC 7899 : dt1 = timestamp2timestamptz_opt_overflow(timestampVal, &overflow);
914 tgl 2254 CBC 7899 : if (overflow > 0)
2255 : {
914 tgl 2256 ECB : /* dt1 is larger than any finite timestamp, but less than infinity */
914 tgl 2257 UIC 0 : return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
2258 : }
914 tgl 2259 GIC 7899 : if (overflow < 0)
914 tgl 2260 ECB : {
2261 : /* dt1 is less than any finite timestamp, but more than -infinity */
914 tgl 2262 CBC 6 : return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
2263 : }
2264 :
914 tgl 2265 GIC 7893 : return timestamptz_cmp_internal(dt1, dt2);
2266 : }
2267 :
2268 : Datum
6957 2269 906 : timestamp_eq_timestamptz(PG_FUNCTION_ARGS)
6957 tgl 2270 ECB : {
6957 tgl 2271 GIC 906 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2272 906 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2273 :
914 tgl 2274 906 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) == 0);
6957 tgl 2275 ECB : }
2276 :
2277 : Datum
6957 tgl 2278 UIC 0 : timestamp_ne_timestamptz(PG_FUNCTION_ARGS)
6957 tgl 2279 EUB : {
6957 tgl 2280 UIC 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2281 LBC 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
2282 :
914 tgl 2283 UIC 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) != 0);
6957 tgl 2284 ECB : }
2285 :
2286 : Datum
6957 tgl 2287 CBC 1602 : timestamp_lt_timestamptz(PG_FUNCTION_ARGS)
2288 : {
6957 tgl 2289 GIC 1602 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2290 1602 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
6957 tgl 2291 ECB :
914 tgl 2292 GIC 1602 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) < 0);
6957 tgl 2293 ECB : }
2294 :
2295 : Datum
6957 tgl 2296 CBC 1599 : timestamp_gt_timestamptz(PG_FUNCTION_ARGS)
2297 : {
6957 tgl 2298 GIC 1599 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2299 1599 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
6957 tgl 2300 EUB :
914 tgl 2301 GIC 1599 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) > 0);
6957 tgl 2302 EUB : }
2303 :
2304 : Datum
6957 tgl 2305 GBC 1899 : timestamp_le_timestamptz(PG_FUNCTION_ARGS)
2306 : {
6957 tgl 2307 GIC 1899 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2308 1899 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
6957 tgl 2309 ECB :
914 tgl 2310 GIC 1899 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) <= 0);
6957 tgl 2311 ECB : }
2312 :
2313 : Datum
6957 tgl 2314 CBC 1752 : timestamp_ge_timestamptz(PG_FUNCTION_ARGS)
2315 : {
6957 tgl 2316 GIC 1752 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2317 1752 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
6957 tgl 2318 ECB :
914 tgl 2319 GIC 1752 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt2) >= 0);
6957 tgl 2320 ECB : }
2321 :
2322 : Datum
6957 tgl 2323 CBC 36 : timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
2324 : {
6957 tgl 2325 GIC 36 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(0);
6797 bruce 2326 36 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
6957 tgl 2327 ECB :
914 tgl 2328 GIC 36 : PG_RETURN_INT32(timestamp_cmp_timestamptz_internal(timestampVal, dt2));
6957 tgl 2329 ECB : }
2330 :
2331 : Datum
6957 tgl 2332 LBC 0 : timestamptz_eq_timestamp(PG_FUNCTION_ARGS)
2333 : {
6797 bruce 2334 UIC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2335 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2336 ECB :
914 tgl 2337 UIC 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) == 0);
6957 tgl 2338 ECB : }
2339 :
2340 : Datum
6957 tgl 2341 CBC 48 : timestamptz_ne_timestamp(PG_FUNCTION_ARGS)
2342 : {
6797 bruce 2343 GIC 48 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2344 48 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2345 ECB :
914 tgl 2346 GIC 48 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) != 0);
6957 tgl 2347 ECB : }
2348 :
2349 : Datum
6957 tgl 2350 LBC 0 : timestamptz_lt_timestamp(PG_FUNCTION_ARGS)
2351 : {
6797 bruce 2352 UIC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2353 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2354 EUB :
914 tgl 2355 UIC 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) > 0);
6957 tgl 2356 EUB : }
2357 :
2358 : Datum
6957 tgl 2359 UBC 0 : timestamptz_gt_timestamp(PG_FUNCTION_ARGS)
2360 : {
6797 bruce 2361 UIC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2362 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2363 ECB :
914 tgl 2364 UIC 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) < 0);
6957 tgl 2365 ECB : }
2366 :
2367 : Datum
6957 tgl 2368 LBC 0 : timestamptz_le_timestamp(PG_FUNCTION_ARGS)
2369 : {
6797 bruce 2370 UIC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2371 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2372 EUB :
914 tgl 2373 UIC 0 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) >= 0);
6957 tgl 2374 EUB : }
2375 :
2376 : Datum
6957 tgl 2377 GBC 3 : timestamptz_ge_timestamp(PG_FUNCTION_ARGS)
2378 : {
6797 bruce 2379 GIC 3 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2380 3 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2381 EUB :
914 tgl 2382 GIC 3 : PG_RETURN_BOOL(timestamp_cmp_timestamptz_internal(timestampVal, dt1) <= 0);
6957 tgl 2383 EUB : }
2384 :
2385 : Datum
6957 tgl 2386 UBC 0 : timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
2387 : {
6797 bruce 2388 UIC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
6957 tgl 2389 0 : Timestamp timestampVal = PG_GETARG_TIMESTAMP(1);
6957 tgl 2390 EUB :
914 tgl 2391 UIC 0 : PG_RETURN_INT32(-timestamp_cmp_timestamptz_internal(timestampVal, dt1));
6957 tgl 2392 EUB : }
2393 :
2394 :
8339 2395 : /*
2396 : * interval_relop - is interval1 relop interval2
2397 : *
2398 : * Interval comparison is based on converting interval values to a linear
2195 tgl 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
5118 tgl 2406 GIC 216874 : interval_cmp_value(const Interval *interval)
2407 : {
2195 tgl 2408 EUB : INT128 span;
2409 : int64 days;
2410 :
2411 : /*
2412 : * Combine the month and day fields into an integral number of days.
560 2413 : * Because the inputs are int32, int64 arithmetic suffices here.
2414 : */
560 tgl 2415 GIC 216874 : days = interval->month * INT64CONST(30);
2195 2416 216874 : days += interval->day;
2417 :
2418 : /* Widen time field to 128 bits */
560 2419 216874 : span = int64_to_int128(interval->time);
2420 :
2421 : /* Scale up days to microseconds, forming a 128-bit product */
2195 2422 216874 : int128_add_int64_mul_int64(&span, days, USECS_PER_DAY);
2423 :
5118 2424 216874 : return span;
2425 : }
2426 :
2427 : static int
267 peter 2428 GNC 107201 : interval_cmp_internal(const Interval *interval1, const Interval *interval2)
2429 : {
2195 tgl 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
8339 tgl 2437 CBC 23354 : interval_eq(PG_FUNCTION_ARGS)
8453 lockhart 2438 ECB : {
8339 tgl 2439 GIC 23354 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2440 23354 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2441 ECB :
8011 tgl 2442 GIC 23354 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) == 0);
2443 : }
8453 lockhart 2444 ECB :
2445 : Datum
8339 tgl 2446 CBC 30 : interval_ne(PG_FUNCTION_ARGS)
2447 : {
8339 tgl 2448 GIC 30 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2449 30 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2450 ECB :
8011 tgl 2451 GIC 30 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) != 0);
8339 tgl 2452 ECB : }
8453 lockhart 2453 :
2454 : Datum
8339 tgl 2455 CBC 45796 : interval_lt(PG_FUNCTION_ARGS)
2456 : {
8339 tgl 2457 GIC 45796 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2458 45796 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2459 ECB :
8011 tgl 2460 GIC 45796 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) < 0);
8339 tgl 2461 ECB : }
8453 lockhart 2462 :
2463 : Datum
8339 tgl 2464 CBC 4788 : interval_gt(PG_FUNCTION_ARGS)
2465 : {
8339 tgl 2466 GIC 4788 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2467 4788 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2468 ECB :
8011 tgl 2469 GIC 4788 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) > 0);
8339 tgl 2470 ECB : }
8453 lockhart 2471 :
2472 : Datum
8339 tgl 2473 CBC 3152 : interval_le(PG_FUNCTION_ARGS)
2474 : {
8339 tgl 2475 GIC 3152 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2476 3152 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2477 ECB :
8011 tgl 2478 GIC 3152 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) <= 0);
8339 tgl 2479 ECB : }
8453 lockhart 2480 :
2481 : Datum
8339 tgl 2482 CBC 2912 : interval_ge(PG_FUNCTION_ARGS)
2483 : {
8339 tgl 2484 GIC 2912 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2485 2912 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2486 ECB :
8011 tgl 2487 GIC 2912 : PG_RETURN_BOOL(interval_cmp_internal(interval1, interval2) >= 0);
8339 tgl 2488 ECB : }
8453 lockhart 2489 :
2490 : Datum
8339 tgl 2491 CBC 26922 : interval_cmp(PG_FUNCTION_ARGS)
2492 : {
8339 tgl 2493 GIC 26922 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
2494 26922 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 2495 ECB :
8011 tgl 2496 GIC 26922 : PG_RETURN_INT32(interval_cmp_internal(interval1, interval2));
8339 tgl 2497 ECB : }
8453 lockhart 2498 :
2499 : /*
5118 tgl 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,
2236 2504 : * and then hash that.
2505 : */
8329 2506 : Datum
8329 tgl 2507 CBC 1137 : interval_hash(PG_FUNCTION_ARGS)
2508 : {
5118 2509 1137 : Interval *interval = PG_GETARG_INTERVAL_P(0);
2195 tgl 2510 GIC 1137 : INT128 span = interval_cmp_value(interval);
2511 : int64 span64;
2512 :
2195 tgl 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 : */
2195 tgl 2519 GIC 1137 : span64 = int128_to_int64(span);
2520 :
2521 1137 : return DirectFunctionCall1(hashint8, Int64GetDatumFast(span64));
2522 : }
2523 :
2524 : Datum
2047 rhaas 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);
2047 rhaas 2529 ECB : int64 span64;
2530 :
2531 : /* Same approach as interval_hash */
2047 rhaas 2532 CBC 30 : span64 = int128_to_int64(span);
2533 :
2047 rhaas 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
8158 tgl 2541 ECB : * because the spec requires us to deliver a non-null answer in some cases
2542 : * where some of the inputs are null.
8426 lockhart 2543 : */
2544 : Datum
8339 tgl 2545 GIC 36 : overlaps_timestamp(PG_FUNCTION_ARGS)
2546 : {
8053 bruce 2547 ECB : /*
2548 : * The arguments are Timestamps, but we leave them as generic Datums to
6385 2549 : * avoid unnecessary conversions between value and reference forms --- not
2550 : * to mention possible dereferences of null pointers.
2551 : */
8339 tgl 2552 GIC 36 : Datum ts1 = PG_GETARG_DATUM(0);
2553 36 : Datum te1 = PG_GETARG_DATUM(1);
8339 tgl 2554 CBC 36 : Datum ts2 = PG_GETARG_DATUM(2);
8339 tgl 2555 GIC 36 : Datum te2 = PG_GETARG_DATUM(3);
8158 tgl 2556 CBC 36 : bool ts1IsNull = PG_ARGISNULL(0);
8158 tgl 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 : /*
6385 bruce 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 : */
8158 tgl 2571 GIC 36 : if (ts1IsNull)
2572 : {
8158 tgl 2573 UIC 0 : if (te1IsNull)
8158 tgl 2574 LBC 0 : PG_RETURN_NULL();
8158 tgl 2575 ECB : /* swap null for non-null */
8426 lockhart 2576 LBC 0 : ts1 = te1;
8158 tgl 2577 0 : te1IsNull = true;
8426 lockhart 2578 ECB : }
8158 tgl 2579 CBC 36 : else if (!te1IsNull)
8426 lockhart 2580 ECB : {
8158 tgl 2581 CBC 36 : if (TIMESTAMP_GT(ts1, te1))
2582 : {
8053 bruce 2583 UIC 0 : Datum tt = ts1;
2584 :
8158 tgl 2585 0 : ts1 = te1;
2586 0 : te1 = tt;
2587 : }
2588 : }
2589 :
2590 : /* Likewise for interval 2. */
8158 tgl 2591 GIC 36 : if (ts2IsNull)
2592 : {
8158 tgl 2593 LBC 0 : if (te2IsNull)
8158 tgl 2594 UIC 0 : PG_RETURN_NULL();
8158 tgl 2595 EUB : /* swap null for non-null */
8426 lockhart 2596 UBC 0 : ts2 = te2;
8158 tgl 2597 UIC 0 : te2IsNull = true;
8426 lockhart 2598 EUB : }
8158 tgl 2599 GBC 36 : else if (!te2IsNull)
2600 : {
8158 tgl 2601 CBC 36 : if (TIMESTAMP_GT(ts2, te2))
2602 : {
8053 bruce 2603 LBC 0 : Datum tt = ts2;
2604 :
8158 tgl 2605 UBC 0 : ts2 = te2;
8158 tgl 2606 UIC 0 : te2 = tt;
8158 tgl 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
8158 tgl 2613 ECB : */
8158 tgl 2614 GIC 36 : if (TIMESTAMP_GT(ts1, ts2))
8158 tgl 2615 EUB : {
8053 bruce 2616 : /*
2617 : * This case is ts1 < te2 OR te1 < te2, which may look redundant but
6385 2618 : * in the presence of nulls it's not quite completely so.
8158 tgl 2619 : */
8158 tgl 2620 UIC 0 : if (te2IsNull)
8158 tgl 2621 LBC 0 : PG_RETURN_NULL();
8158 tgl 2622 UIC 0 : if (TIMESTAMP_LT(ts1, te2))
8158 tgl 2623 LBC 0 : PG_RETURN_BOOL(true);
8158 tgl 2624 UIC 0 : if (te1IsNull)
8158 tgl 2625 UBC 0 : PG_RETURN_NULL();
2626 :
8053 bruce 2627 EUB : /*
6385 2628 : * If te1 is not null then we had ts1 <= te1 above, and we just found
2629 : * ts1 >= te2, hence te1 >= te2.
2630 : */
8158 tgl 2631 UIC 0 : PG_RETURN_BOOL(false);
2632 : }
8158 tgl 2633 GIC 36 : else if (TIMESTAMP_LT(ts1, ts2))
2634 : {
2635 : /* This case is ts2 < te1 OR te2 < te1 */
8158 tgl 2636 CBC 30 : if (te1IsNull)
8158 tgl 2637 UIC 0 : PG_RETURN_NULL();
8158 tgl 2638 GIC 30 : if (TIMESTAMP_LT(ts2, te1))
2639 12 : PG_RETURN_BOOL(true);
2640 18 : if (te2IsNull)
8158 tgl 2641 UIC 0 : PG_RETURN_NULL();
8053 bruce 2642 EUB :
2643 : /*
6385 2644 : * If te2 is not null then we had ts2 <= te2 above, and we just found
2645 : * ts2 >= te1, hence te2 >= te1.
8158 tgl 2646 : */
8158 tgl 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
2578 rhaas 2653 EUB : * rather silly way of saying "true if both are non-null, else null".
2654 : */
8158 tgl 2655 CBC 6 : if (te1IsNull || te2IsNull)
8158 tgl 2656 UIC 0 : PG_RETURN_NULL();
8158 tgl 2657 GIC 6 : PG_RETURN_BOOL(true);
8158 tgl 2658 ECB : }
8339 tgl 2659 EUB :
8339 tgl 2660 ECB : #undef TIMESTAMP_GT
2661 : #undef TIMESTAMP_LT
2662 : }
8426 lockhart 2663 EUB :
2664 :
2665 : /*----------------------------------------------------------
2666 : * "Arithmetic" operators on date/times.
2667 : *---------------------------------------------------------*/
2668 :
8339 tgl 2669 ECB : Datum
8339 tgl 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 */
7184 tgl 2677 LBC 0 : if (timestamp_cmp_internal(dt1, dt2) < 0)
7184 tgl 2678 UBC 0 : result = dt1;
7184 tgl 2679 ECB : else
7184 tgl 2680 UIC 0 : result = dt2;
8339 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 :
7184 2691 0 : if (timestamp_cmp_internal(dt1, dt2) > 0)
7184 tgl 2692 UBC 0 : result = dt1;
2693 : else
2694 0 : result = dt2;
8339 2695 0 : PG_RETURN_TIMESTAMP(result);
2696 : }
2697 :
2698 :
8339 tgl 2699 EUB : Datum
8339 tgl 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 :
8339 tgl 2706 GIC 2924 : result = (Interval *) palloc(sizeof(Interval));
8453 lockhart 2707 EUB :
7863 lockhart 2708 GIC 2924 : if (TIMESTAMP_NOT_FINITE(dt1) || TIMESTAMP_NOT_FINITE(dt2))
7196 tgl 2709 UBC 0 : ereport(ERROR,
7196 tgl 2710 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2711 : errmsg("cannot subtract infinite timestamps")));
2712 :
48 tgl 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")));
7863 lockhart 2717 EUB :
8453 lockhart 2718 GIC 2918 : result->month = 0;
6472 bruce 2719 GBC 2918 : result->day = 0;
6472 bruce 2720 EUB :
2721 : /*----------
2722 : * This is wrong, but removing it breaks a lot of regression tests.
2723 : * For example:
2724 : *
6347 tgl 2725 ECB : * test=> SET timezone = 'EST5EDT';
2726 : * test=> SELECT
2727 : * test-> ('2005-10-30 13:22:00-05'::timestamptz -
6031 bruce 2728 : * test(> '2005-10-29 13:22:00-04'::timestamptz);
2729 : * ?column?
2730 : * ----------------
6347 tgl 2731 : * 1 day 01:00:00
2732 : * (1 row)
6373 bruce 2733 : *
6347 tgl 2734 EUB : * so adding that to the first timestamp gets:
2735 : *
2736 : * test=> SELECT
2737 : * test-> ('2005-10-29 13:22:00-04'::timestamptz +
6347 tgl 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 : */
6347 bruce 2746 GIC 2918 : result = DatumGetIntervalP(DirectFunctionCall1(interval_justify_hours,
2747 : IntervalPGetDatum(result)));
2748 :
6436 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
6243 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;
6243 bruce 2771 ECB :
6243 bruce 2772 GIC 27 : result = (Interval *) palloc(sizeof(Interval));
2773 27 : result->month = span->month;
6243 bruce 2774 CBC 27 : result->day = span->day;
6243 bruce 2775 GIC 27 : result->time = span->time;
2776 :
2777 : /* pre-justify days if it might prevent overflow */
405 tgl 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))
405 tgl 2784 UIC 0 : ereport(ERROR,
2785 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2786 : errmsg("interval out of range")));
2787 : }
2788 :
2789 : /*
405 tgl 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 : */
6243 bruce 2795 GIC 27 : TMODULO(result->time, wholeday, USECS_PER_DAY);
405 tgl 2796 27 : result->day += wholeday;
6243 bruce 2797 ECB :
6243 bruce 2798 CBC 27 : wholemonth = result->day / DAYS_PER_MONTH;
2799 27 : result->day -= wholemonth * DAYS_PER_MONTH;
405 tgl 2800 27 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
405 tgl 2801 GIC 12 : ereport(ERROR,
2802 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
405 tgl 2803 ECB : errmsg("interval out of range")));
6243 bruce 2804 :
6243 bruce 2805 GIC 15 : if (result->month > 0 &&
6243 bruce 2806 CBC 9 : (result->day < 0 || (result->day == 0 && result->time < 0)))
6243 bruce 2807 ECB : {
6243 bruce 2808 CBC 3 : result->day += DAYS_PER_MONTH;
6243 bruce 2809 GBC 3 : result->month--;
2810 : }
6243 bruce 2811 GIC 12 : else if (result->month < 0 &&
6031 2812 6 : (result->day > 0 || (result->day == 0 && result->time > 0)))
2813 : {
6243 bruce 2814 UIC 0 : result->day -= DAYS_PER_MONTH;
2815 0 : result->month++;
2816 : }
2817 :
6243 bruce 2818 GIC 15 : if (result->day > 0 && result->time < 0)
2819 : {
6243 bruce 2820 CBC 3 : result->time += USECS_PER_DAY;
2821 3 : result->day--;
2822 : }
2823 12 : else if (result->day < 0 && result->time > 0)
6031 bruce 2824 ECB : {
6243 bruce 2825 LBC 0 : result->time -= USECS_PER_DAY;
2826 0 : result->day++;
2827 : }
2828 :
6243 bruce 2829 GIC 15 : PG_RETURN_INTERVAL_P(result);
6243 bruce 2830 ECB : }
2831 :
2832 : /*
6375 tgl 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
6472 bruce 2837 : * situations (such as non-TZ) where '1 day' = '24 hours' is valid,
2838 : * e.g. interval subtraction and division.
6472 bruce 2839 EUB : */
2840 : Datum
6472 bruce 2841 GIC 3914 : interval_justify_hours(PG_FUNCTION_ARGS)
2842 : {
6385 bruce 2843 CBC 3914 : Interval *span = PG_GETARG_INTERVAL_P(0);
2844 : Interval *result;
5497 tgl 2845 ECB : TimeOffset wholeday;
6472 bruce 2846 :
6472 bruce 2847 GIC 3914 : result = (Interval *) palloc(sizeof(Interval));
6472 bruce 2848 CBC 3914 : result->month = span->month;
6375 tgl 2849 GIC 3914 : result->day = span->day;
6472 bruce 2850 GBC 3914 : result->time = span->time;
6472 bruce 2851 EUB :
6375 tgl 2852 GIC 3914 : TMODULO(result->time, wholeday, USECS_PER_DAY);
405 2853 3914 : if (pg_add_s32_overflow(result->day, wholeday, &result->day))
405 tgl 2854 CBC 3 : ereport(ERROR,
2855 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2856 : errmsg("interval out of range")));
2857 :
6243 bruce 2858 GIC 3911 : if (result->day > 0 && result->time < 0)
2859 : {
6243 bruce 2860 UIC 0 : result->time += USECS_PER_DAY;
2861 0 : result->day--;
2862 : }
6243 bruce 2863 GIC 3911 : else if (result->day < 0 && result->time > 0)
2864 : {
6243 bruce 2865 UIC 0 : result->time -= USECS_PER_DAY;
6243 bruce 2866 LBC 0 : result->day++;
2867 : }
6243 bruce 2868 ECB :
8339 tgl 2869 GIC 3911 : PG_RETURN_INTERVAL_P(result);
2870 : }
2871 :
6375 tgl 2872 ECB : /*
2873 : * interval_justify_days()
2874 : *
2875 : * Adjust interval so 'day' contains less than 30 days, adding
2876 : * the excess to 'month'.
6472 bruce 2877 : */
2878 : Datum
6472 bruce 2879 CBC 996 : interval_justify_days(PG_FUNCTION_ARGS)
2880 : {
6385 bruce 2881 GIC 996 : Interval *span = PG_GETARG_INTERVAL_P(0);
2882 : Interval *result;
6375 tgl 2883 ECB : int32 wholemonth;
2884 :
6472 bruce 2885 GBC 996 : result = (Interval *) palloc(sizeof(Interval));
6375 tgl 2886 996 : result->month = span->month;
6472 bruce 2887 GIC 996 : result->day = span->day;
6472 bruce 2888 CBC 996 : result->time = span->time;
2889 :
6375 tgl 2890 GBC 996 : wholemonth = result->day / DAYS_PER_MONTH;
2891 996 : result->day -= wholemonth * DAYS_PER_MONTH;
405 tgl 2892 GIC 996 : if (pg_add_s32_overflow(result->month, wholemonth, &result->month))
2893 3 : ereport(ERROR,
405 tgl 2894 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2895 : errmsg("interval out of range")));
2896 :
6243 bruce 2897 GIC 993 : if (result->month > 0 && result->day < 0)
2898 : {
6243 bruce 2899 UIC 0 : result->day += DAYS_PER_MONTH;
2900 0 : result->month--;
2901 : }
6243 bruce 2902 GIC 993 : else if (result->month < 0 && result->day > 0)
2903 : {
6243 bruce 2904 LBC 0 : result->day -= DAYS_PER_MONTH;
6243 bruce 2905 UIC 0 : result->month++;
6243 bruce 2906 ECB : }
2907 :
6472 bruce 2908 GIC 993 : PG_RETURN_INTERVAL_P(result);
2909 : }
8453 lockhart 2910 ECB :
6994 tgl 2911 : /* timestamp_pl_interval()
2881 heikki.linnakangas 2912 : * Add an interval to a timestamp data type.
6472 bruce 2913 : * Note that interval has provisions for qualitative year/month and day
2914 : * units, so try to do the right thing with them.
8453 lockhart 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.
6472 bruce 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
6994 tgl 2922 CBC 4369 : timestamp_pl_interval(PG_FUNCTION_ARGS)
2923 : {
6385 bruce 2924 GBC 4369 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
8339 tgl 2925 4369 : Interval *span = PG_GETARG_INTERVAL_P(1);
2926 : Timestamp result;
7863 lockhart 2927 ECB :
7863 lockhart 2928 GIC 4369 : if (TIMESTAMP_NOT_FINITE(timestamp))
7863 lockhart 2929 GBC 12 : result = timestamp;
7863 lockhart 2930 EUB : else
2931 : {
7863 lockhart 2932 GIC 4357 : if (span->month != 0)
7863 lockhart 2933 ECB : {
2934 : struct pg_tm tt,
7863 lockhart 2935 GIC 1293 : *tm = &tt;
2936 : fsec_t fsec;
2937 :
6471 bruce 2938 1293 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
7196 tgl 2939 UIC 0 : ereport(ERROR,
2940 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2941 : errmsg("timestamp out of range")));
2942 :
7196 tgl 2943 GIC 1293 : tm->tm_mon += span->month;
6471 bruce 2944 1293 : if (tm->tm_mon > MONTHS_PER_YEAR)
2945 : {
2946 690 : tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
6471 bruce 2947 CBC 690 : tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1;
2948 : }
7196 tgl 2949 603 : else if (tm->tm_mon < 1)
7863 lockhart 2950 ECB : {
6471 bruce 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;
7863 lockhart 2953 ECB : }
7196 tgl 2954 :
2955 : /* adjust for end of month boundary problems... */
7196 tgl 2956 GIC 1293 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
7196 tgl 2957 CBC 6 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
2958 :
6471 bruce 2959 GIC 1293 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
7196 tgl 2960 LBC 0 : ereport(ERROR,
2961 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2962 : errmsg("timestamp out of range")));
7863 lockhart 2963 ECB : }
7863 lockhart 2964 EUB :
6472 bruce 2965 GIC 4357 : if (span->day != 0)
2966 : {
2967 : struct pg_tm tt,
6472 bruce 2968 CBC 1329 : *tm = &tt;
6472 bruce 2969 ECB : fsec_t fsec;
2970 : int julian;
6385 2971 :
6471 bruce 2972 CBC 1329 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
6472 bruce 2973 UIC 0 : ereport(ERROR,
6472 bruce 2974 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2975 : errmsg("timestamp out of range")));
2976 :
2578 rhaas 2977 : /* Add days by converting to and from Julian */
6472 bruce 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 :
6471 bruce 2981 CBC 1329 : if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0)
6472 bruce 2982 LBC 0 : ereport(ERROR,
2983 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6472 bruce 2984 ECB : errmsg("timestamp out of range")));
6472 bruce 2985 EUB : }
2986 :
6472 bruce 2987 GIC 4357 : timestamp += span->time;
2988 :
2580 tgl 2989 4357 : if (!IS_VALID_TIMESTAMP(timestamp))
2580 tgl 2990 LBC 0 : ereport(ERROR,
2991 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2992 : errmsg("timestamp out of range")));
2580 tgl 2993 ECB :
7863 lockhart 2994 GIC 4357 : result = timestamp;
2995 : }
2996 :
7863 lockhart 2997 CBC 4369 : PG_RETURN_TIMESTAMP(result);
7863 lockhart 2998 EUB : }
2999 :
3000 : Datum
6994 tgl 3001 GIC 912 : timestamp_mi_interval(PG_FUNCTION_ARGS)
3002 : {
6385 bruce 3003 CBC 912 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
7863 lockhart 3004 912 : Interval *span = PG_GETARG_INTERVAL_P(1);
3005 : Interval tspan;
7863 lockhart 3006 ECB :
7863 lockhart 3007 GBC 912 : tspan.month = -span->month;
6472 bruce 3008 GIC 912 : tspan.day = -span->day;
7863 lockhart 3009 912 : tspan.time = -span->time;
3010 :
6994 tgl 3011 912 : return DirectFunctionCall2(timestamp_pl_interval,
7863 lockhart 3012 ECB : TimestampGetDatum(timestamp),
3013 : PointerGetDatum(&tspan));
3014 : }
7863 lockhart 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.
7863 lockhart 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
22 tgl 3029 GNC 48294 : timestamptz_pl_interval_internal(TimestampTz timestamp,
3030 : Interval *span,
3031 : pg_tz *attimezone)
7863 lockhart 3032 ECB : {
3033 : TimestampTz result;
8453 3034 : int tz;
3035 :
8339 tgl 3036 CBC 48294 : if (TIMESTAMP_NOT_FINITE(timestamp))
8339 tgl 3037 GIC 12 : result = timestamp;
8453 lockhart 3038 ECB : else
3039 : {
3040 : /* Use session timezone if caller asks for default */
22 tgl 3041 GNC 48282 : if (attimezone == NULL)
3042 17263 : attimezone = session_timezone;
3043 :
8453 lockhart 3044 GIC 48282 : if (span->month != 0)
3045 : {
3046 : struct pg_tm tt,
3047 1149 : *tm = &tt;
3048 : fsec_t fsec;
3049 :
22 tgl 3050 GNC 1149 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
7196 tgl 3051 UIC 0 : ereport(ERROR,
3052 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3053 : errmsg("timestamp out of range")));
3054 :
7196 tgl 3055 GIC 1149 : tm->tm_mon += span->month;
6471 bruce 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;
8453 lockhart 3060 ECB : }
7196 tgl 3061 GIC 711 : else if (tm->tm_mon < 1)
3062 : {
6471 bruce 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 :
7196 tgl 3067 ECB : /* adjust for end of month boundary problems... */
7196 tgl 3068 CBC 1149 : if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
7196 tgl 3069 GIC 27 : tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
3070 :
22 tgl 3071 GNC 1149 : tz = DetermineTimeZoneOffset(tm, attimezone);
7196 tgl 3072 ECB :
6471 bruce 3073 CBC 1149 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
7196 tgl 3074 UIC 0 : ereport(ERROR,
7196 tgl 3075 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3076 : errmsg("timestamp out of range")));
3077 : }
8453 lockhart 3078 :
6472 bruce 3079 GIC 48282 : if (span->day != 0)
3080 : {
6472 bruce 3081 ECB : struct pg_tm tt,
6472 bruce 3082 GBC 1531 : *tm = &tt;
3083 : fsec_t fsec;
3084 : int julian;
3085 :
22 tgl 3086 GNC 1531 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, attimezone) != 0)
6472 bruce 3087 LBC 0 : ereport(ERROR,
3088 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
6472 bruce 3089 ECB : errmsg("timestamp out of range")));
3090 :
3091 : /* Add days by converting to and from Julian */
6472 bruce 3092 CBC 1531 : julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
6472 bruce 3093 GIC 1531 : j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
6472 bruce 3094 ECB :
22 tgl 3095 GNC 1531 : tz = DetermineTimeZoneOffset(tm, attimezone);
3096 :
6471 bruce 3097 GIC 1531 : if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
6472 bruce 3098 UIC 0 : ereport(ERROR,
6472 bruce 3099 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3100 : errmsg("timestamp out of range")));
3101 : }
3102 :
6472 bruce 3103 GIC 48282 : timestamp += span->time;
2580 tgl 3104 ECB :
2580 tgl 3105 GBC 48282 : if (!IS_VALID_TIMESTAMP(timestamp))
2580 tgl 3106 UIC 0 : ereport(ERROR,
3107 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3108 : errmsg("timestamp out of range")));
3109 :
7863 lockhart 3110 CBC 48282 : result = timestamp;
3111 : }
3112 :
22 tgl 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 :
8053 bruce 3126 807 : tspan.month = -span->month;
6472 3127 807 : tspan.day = -span->day;
8053 3128 807 : tspan.time = -span->time;
3129 :
22 tgl 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
22 tgl 3146 CBC 699 : timestamptz_mi_interval(PG_FUNCTION_ARGS)
22 tgl 3147 EUB : {
22 tgl 3148 GIC 699 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
3149 699 : Interval *span = PG_GETARG_INTERVAL_P(1);
3150 :
22 tgl 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
8339 tgl 3180 CBC 1251 : interval_um(PG_FUNCTION_ARGS)
3181 : {
3182 1251 : Interval *interval = PG_GETARG_INTERVAL_P(0);
8453 lockhart 3183 EUB : Interval *result;
3184 :
8339 tgl 3185 GIC 1251 : result = (Interval *) palloc(sizeof(Interval));
3186 :
6471 bruce 3187 CBC 1251 : result->time = -interval->time;
3188 : /* overflow check copied from int4um */
3356 bruce 3189 GIC 1251 : if (interval->time != 0 && SAMESIGN(result->time, interval->time))
3356 bruce 3190 LBC 0 : ereport(ERROR,
3191 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3192 : errmsg("interval out of range")));
6471 bruce 3193 GIC 1251 : result->day = -interval->day;
3356 3194 1251 : if (interval->day != 0 && SAMESIGN(result->day, interval->day))
3356 bruce 3195 UIC 0 : ereport(ERROR,
3196 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3197 ECB : errmsg("interval out of range")));
6471 bruce 3198 GIC 1251 : result->month = -interval->month;
3356 3199 1251 : if (interval->month != 0 && SAMESIGN(result->month, interval->month))
3356 bruce 3200 UIC 0 : ereport(ERROR,
3201 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3202 : errmsg("interval out of range")));
8453 lockhart 3203 ECB :
8339 tgl 3204 CBC 1251 : PG_RETURN_INTERVAL_P(result);
8339 tgl 3205 ECB : }
3206 :
8453 lockhart 3207 :
3208 : Datum
8339 tgl 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;
7522 bruce 3214 ECB :
3215 : /* use interval_cmp_internal to be sure this agrees with comparisons */
7184 tgl 3216 LBC 0 : if (interval_cmp_internal(interval1, interval2) < 0)
3217 0 : result = interval1;
3218 : else
3219 0 : result = interval2;
8339 tgl 3220 UIC 0 : PG_RETURN_INTERVAL_P(result);
3221 : }
3222 :
8339 tgl 3223 ECB : Datum
8339 tgl 3224 UIC 0 : interval_larger(PG_FUNCTION_ARGS)
8453 lockhart 3225 ECB : {
8339 tgl 3226 LBC 0 : Interval *interval1 = PG_GETARG_INTERVAL_P(0);
8339 tgl 3227 UIC 0 : Interval *interval2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 3228 ECB : Interval *result;
3229 :
7184 tgl 3230 UIC 0 : if (interval_cmp_internal(interval1, interval2) > 0)
3231 0 : result = interval1;
3232 : else
3233 0 : result = interval2;
8339 3234 0 : PG_RETURN_INTERVAL_P(result);
8339 tgl 3235 ECB : }
3236 :
3237 : Datum
8339 tgl 3238 CBC 183 : interval_pl(PG_FUNCTION_ARGS)
8453 lockhart 3239 ECB : {
8339 tgl 3240 CBC 183 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
8339 tgl 3241 GIC 183 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 3242 ECB : Interval *result;
3243 :
8339 tgl 3244 GIC 183 : result = (Interval *) palloc(sizeof(Interval));
3245 :
6471 bruce 3246 CBC 183 : result->month = span1->month + span2->month;
3247 : /* overflow check copied from int4pl */
3356 3248 183 : if (SAMESIGN(span1->month, span2->month) &&
3249 180 : !SAMESIGN(result->month, span1->month))
3356 bruce 3250 LBC 0 : ereport(ERROR,
3356 bruce 3251 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3252 : errmsg("interval out of range")));
3253 :
6471 bruce 3254 GIC 183 : result->day = span1->day + span2->day;
3356 3255 183 : if (SAMESIGN(span1->day, span2->day) &&
3256 183 : !SAMESIGN(result->day, span1->day))
3356 bruce 3257 LBC 0 : ereport(ERROR,
3258 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3259 ECB : errmsg("interval out of range")));
3260 :
6471 bruce 3261 GIC 183 : result->time = span1->time + span2->time;
3356 bruce 3262 CBC 183 : if (SAMESIGN(span1->time, span2->time) &&
3356 bruce 3263 GIC 177 : !SAMESIGN(result->time, span1->time))
3356 bruce 3264 LBC 0 : ereport(ERROR,
3265 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3266 ECB : errmsg("interval out of range")));
8453 lockhart 3267 EUB :
8339 tgl 3268 GIC 183 : PG_RETURN_INTERVAL_P(result);
3269 : }
8453 lockhart 3270 ECB :
8339 tgl 3271 : Datum
8339 tgl 3272 GBC 723 : interval_mi(PG_FUNCTION_ARGS)
3273 : {
8339 tgl 3274 GIC 723 : Interval *span1 = PG_GETARG_INTERVAL_P(0);
8339 tgl 3275 CBC 723 : Interval *span2 = PG_GETARG_INTERVAL_P(1);
8453 lockhart 3276 ECB : Interval *result;
8453 lockhart 3277 EUB :
8339 tgl 3278 GIC 723 : result = (Interval *) palloc(sizeof(Interval));
3279 :
6471 bruce 3280 723 : result->month = span1->month - span2->month;
3356 bruce 3281 ECB : /* overflow check copied from int4mi */
3356 bruce 3282 GIC 723 : if (!SAMESIGN(span1->month, span2->month) &&
3356 bruce 3283 UIC 0 : !SAMESIGN(result->month, span1->month))
3284 0 : ereport(ERROR,
3285 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3286 EUB : errmsg("interval out of range")));
3287 :
6471 bruce 3288 GBC 723 : result->day = span1->day - span2->day;
3356 3289 723 : if (!SAMESIGN(span1->day, span2->day) &&
3356 bruce 3290 GIC 321 : !SAMESIGN(result->day, span1->day))
3356 bruce 3291 UIC 0 : ereport(ERROR,
3292 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3293 EUB : errmsg("interval out of range")));
3294 :
6471 bruce 3295 GIC 723 : result->time = span1->time - span2->time;
3356 bruce 3296 GBC 723 : if (!SAMESIGN(span1->time, span2->time) &&
3297 321 : !SAMESIGN(result->time, span1->time))
3356 bruce 3298 UIC 0 : ereport(ERROR,
3299 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3300 : errmsg("interval out of range")));
3356 bruce 3301 EUB :
8339 tgl 3302 GIC 723 : PG_RETURN_INTERVAL_P(result);
8339 tgl 3303 EUB : }
8453 lockhart 3304 :
3305 : /*
3306 : * There is no interval_abs(): it is unclear what value to return:
4790 bruce 3307 : * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php
3308 : * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php
3309 : */
3310 :
8339 tgl 3311 : Datum
8339 tgl 3312 GIC 5766 : interval_mul(PG_FUNCTION_ARGS)
3313 : {
6468 bruce 3314 5766 : Interval *span = PG_GETARG_INTERVAL_P(0);
8339 tgl 3315 CBC 5766 : float8 factor = PG_GETARG_FLOAT8(1);
3316 : double month_remainder_days,
3356 bruce 3317 ECB : sec_remainder,
3318 : result_double;
6031 bruce 3319 GIC 5766 : int32 orig_month = span->month,
3320 5766 : orig_day = span->day;
6436 bruce 3321 ECB : Interval *result;
3322 :
8339 tgl 3323 CBC 5766 : result = (Interval *) palloc(sizeof(Interval));
3324 :
3356 bruce 3325 5766 : result_double = span->month * factor;
2567 tgl 3326 5766 : if (isnan(result_double) ||
2567 tgl 3327 GBC 5766 : result_double > INT_MAX || result_double < INT_MIN)
3356 bruce 3328 UIC 0 : ereport(ERROR,
3329 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3330 : errmsg("interval out of range")));
3356 bruce 3331 CBC 5766 : result->month = (int32) result_double;
3356 bruce 3332 ECB :
3356 bruce 3333 CBC 5766 : result_double = span->day * factor;
2567 tgl 3334 GBC 5766 : if (isnan(result_double) ||
2567 tgl 3335 GIC 5766 : result_double > INT_MAX || result_double < INT_MIN)
3356 bruce 3336 UIC 0 : ereport(ERROR,
3337 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3356 bruce 3338 ECB : errmsg("interval out of range")));
3356 bruce 3339 CBC 5766 : result->day = (int32) result_double;
6468 bruce 3340 ECB :
6375 tgl 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
6375 tgl 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 :
6062 bruce 3351 : /*
6031 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 : */
6060 bruce 3359 CBC 5766 : month_remainder_days = (orig_month * factor - result->month) * DAYS_PER_MONTH;
6060 bruce 3360 GBC 5766 : month_remainder_days = TSROUND(month_remainder_days);
3361 5766 : sec_remainder = (orig_day * factor - result->day +
2118 tgl 3362 GIC 5766 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
6060 bruce 3363 5766 : sec_remainder = TSROUND(sec_remainder);
3364 :
6060 bruce 3365 ECB : /*
6031 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
6031 bruce 3368 EUB : * of cascade and the seconds factor operation itself.
3369 : */
184 peter 3370 GNC 5766 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3371 : {
6031 bruce 3372 LBC 0 : result->day += (int) (sec_remainder / SECS_PER_DAY);
3373 0 : sec_remainder -= (int) (sec_remainder / SECS_PER_DAY) * SECS_PER_DAY;
6060 bruce 3374 ECB : }
6468 bruce 3375 EUB :
3376 : /* cascade units down */
6062 bruce 3377 GIC 5766 : result->day += (int32) month_remainder_days;
3356 3378 5766 : result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
1249 tgl 3379 CBC 5766 : if (isnan(result_double) || !FLOAT8_FITS_IN_INT64(result_double))
3356 bruce 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 :
6436 3385 5763 : PG_RETURN_INTERVAL_P(result);
3386 : }
3387 :
3388 : Datum
8339 tgl 3389 CBC 5715 : mul_d_interval(PG_FUNCTION_ARGS)
3390 : {
8339 tgl 3391 ECB : /* Args are float8 and Interval *, but leave them as generic Datum */
8339 tgl 3392 CBC 5715 : Datum factor = PG_GETARG_DATUM(0);
6468 bruce 3393 GIC 5715 : Datum span = PG_GETARG_DATUM(1);
3394 :
3395 5715 : return DirectFunctionCall2(interval_mul, span, factor);
8339 tgl 3396 ECB : }
3397 :
3398 : Datum
8339 tgl 3399 GIC 57 : interval_div(PG_FUNCTION_ARGS)
8453 lockhart 3400 ECB : {
7658 lockhart 3401 GIC 57 : Interval *span = PG_GETARG_INTERVAL_P(0);
8339 tgl 3402 CBC 57 : float8 factor = PG_GETARG_FLOAT8(1);
6031 bruce 3403 ECB : double month_remainder_days,
3404 : sec_remainder;
6031 bruce 3405 GBC 57 : int32 orig_month = span->month,
6031 bruce 3406 GIC 57 : orig_day = span->day;
3407 : Interval *result;
6031 bruce 3408 ECB :
8339 tgl 3409 GIC 57 : result = (Interval *) palloc(sizeof(Interval));
8453 lockhart 3410 ECB :
8339 tgl 3411 CBC 57 : if (factor == 0.0)
7196 tgl 3412 LBC 0 : ereport(ERROR,
7196 tgl 3413 EUB : (errcode(ERRCODE_DIVISION_BY_ZERO),
3414 : errmsg("division by zero")));
3415 :
6062 bruce 3416 CBC 57 : result->month = (int32) (span->month / factor);
6062 bruce 3417 GIC 57 : result->day = (int32) (span->day / factor);
3418 :
3419 : /*
3420 : * Fractional months full days into days. See comment in interval_mul().
3421 : */
6060 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 +
2118 tgl 3425 57 : month_remainder_days - (int) month_remainder_days) * SECS_PER_DAY;
6060 bruce 3426 57 : sec_remainder = TSROUND(sec_remainder);
184 peter 3427 GNC 57 : if (fabs(sec_remainder) >= SECS_PER_DAY)
3428 : {
6031 bruce 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 */
6375 tgl 3434 57 : result->day += (int32) month_remainder_days;
6062 bruce 3435 57 : result->time = rint(span->time / factor + sec_remainder * USECS_PER_SEC);
8453 lockhart 3436 ECB :
6436 bruce 3437 CBC 57 : PG_RETURN_INTERVAL_P(result);
8339 tgl 3438 ECB : }
8453 lockhart 3439 :
1887 tgl 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 : */
1887 tgl 3449 EUB :
3450 : Datum
1887 tgl 3451 GIC 210 : in_range_timestamptz_interval(PG_FUNCTION_ARGS)
3452 : {
3453 210 : TimestampTz val = PG_GETARG_TIMESTAMPTZ(0);
1887 tgl 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)
1887 tgl 3461 UIC 0 : ereport(ERROR,
1763 peter_e 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 */
1887 tgl 3466 CBC 210 : if (sub)
22 tgl 3467 GNC 105 : sum = timestamptz_mi_interval_internal(base, offset, NULL);
1887 tgl 3468 ECB : else
22 tgl 3469 GNC 105 : sum = timestamptz_pl_interval_internal(base, offset, NULL);
3470 :
1887 tgl 3471 GIC 210 : if (less)
1887 tgl 3472 CBC 105 : PG_RETURN_BOOL(val <= sum);
3473 : else
3474 105 : PG_RETURN_BOOL(val >= sum);
1887 tgl 3475 ECB : }
3476 :
3477 : Datum
1887 tgl 3478 CBC 879 : in_range_timestamp_interval(PG_FUNCTION_ARGS)
1887 tgl 3479 ECB : {
1887 tgl 3480 GIC 879 : Timestamp val = PG_GETARG_TIMESTAMP(0);
3481 879 : Timestamp base = PG_GETARG_TIMESTAMP(1);
1887 tgl 3482 CBC 879 : Interval *offset = PG_GETARG_INTERVAL_P(2);
1887 tgl 3483 GIC 879 : bool sub = PG_GETARG_BOOL(3);
1887 tgl 3484 CBC 879 : bool less = PG_GETARG_BOOL(4);
1887 tgl 3485 EUB : Timestamp sum;
3486 :
1887 tgl 3487 GIC 879 : if (int128_compare(interval_cmp_value(offset), int64_to_int128(0)) < 0)
3488 3 : ereport(ERROR,
1763 peter_e 3489 ECB : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
1887 tgl 3490 : errmsg("invalid preceding or following size in window function")));
3491 :
3492 : /* We don't currently bother to avoid overflow hazards here */
1887 tgl 3493 GIC 876 : if (sub)
3494 381 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_mi_interval,
1887 tgl 3495 ECB : TimestampGetDatum(base),
3496 : IntervalPGetDatum(offset)));
3497 : else
1887 tgl 3498 CBC 495 : sum = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
1887 tgl 3499 ECB : TimestampGetDatum(base),
3500 : IntervalPGetDatum(offset)));
3501 :
1887 tgl 3502 CBC 876 : if (less)
3503 534 : PG_RETURN_BOOL(val <= sum);
3504 : else
1887 tgl 3505 GIC 342 : PG_RETURN_BOOL(val >= sum);
3506 : }
1887 tgl 3507 ECB :
3508 : Datum
1887 tgl 3509 GIC 216 : in_range_interval_interval(PG_FUNCTION_ARGS)
1887 tgl 3510 ECB : {
1887 tgl 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)
1887 tgl 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 */
1887 tgl 3524 CBC 216 : if (sub)
1887 tgl 3525 GIC 108 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
1887 tgl 3526 ECB : IntervalPGetDatum(base),
3527 : IntervalPGetDatum(offset)));
3528 : else
1887 tgl 3529 CBC 108 : sum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
1887 tgl 3530 ECB : IntervalPGetDatum(base),
3531 : IntervalPGetDatum(offset)));
3532 :
1887 tgl 3533 CBC 216 : if (less)
1887 tgl 3534 GBC 108 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) <= 0);
3535 : else
1887 tgl 3536 GIC 108 : PG_RETURN_BOOL(interval_cmp_internal(val, sum) >= 0);
3537 : }
3538 :
1887 tgl 3539 ECB :
8301 3540 : /*
3541 : * interval_accum, interval_accum_inv, and interval_avg implement the
3284 3542 : * AVG(interval) aggregate.
3543 : *
8301 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
8301 tgl 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);
8301 tgl 3555 ECB : Datum *transdatums;
3556 : int ndatums;
3557 : Interval sumX,
3558 : N;
3559 : Interval *newsum;
3560 : ArrayType *result;
3561 :
8301 tgl 3562 GIC 36 : deconstruct_array(transarray,
3563 : INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3564 : &transdatums, NULL, &ndatums);
3565 36 : if (ndatums != 2)
7196 tgl 3566 LBC 0 : elog(ERROR, "expected 2-element interval array");
8053 bruce 3567 ECB :
3284 tgl 3568 GIC 36 : sumX = *(DatumGetIntervalP(transdatums[0]));
3569 36 : N = *(DatumGetIntervalP(transdatums[1]));
3570 :
8301 tgl 3571 CBC 36 : newsum = DatumGetIntervalP(DirectFunctionCall2(interval_pl,
3572 : IntervalPGetDatum(&sumX),
3573 : IntervalPGetDatum(newval)));
8301 tgl 3574 GIC 36 : N.time += 1;
8301 tgl 3575 ECB :
8301 tgl 3576 CBC 36 : transdatums[0] = IntervalPGetDatum(newsum);
8301 tgl 3577 GIC 36 : transdatums[1] = IntervalPGetDatum(&N);
8301 tgl 3578 ECB :
8301 tgl 3579 GIC 36 : result = construct_array(transdatums, 2,
3580 : INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE);
3581 :
8301 tgl 3582 CBC 36 : PG_RETURN_ARRAYTYPE_P(result);
3583 : }
8301 tgl 3584 ECB :
2560 rhaas 3585 : Datum
2560 rhaas 3586 LBC 0 : interval_combine(PG_FUNCTION_ARGS)
2560 rhaas 3587 ECB : {
2560 rhaas 3588 LBC 0 : ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
2560 rhaas 3589 UIC 0 : ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
3590 : Datum *transdatums1;
2560 rhaas 3591 ECB : Datum *transdatums2;
2560 rhaas 3592 EUB : int ndatums1;
3593 : int ndatums2;
3594 : Interval sum1,
3595 : N1;
3596 : Interval sum2,
2560 rhaas 3597 ECB : N2;
3598 :
3599 : Interval *newsum;
3600 : ArrayType *result;
3601 :
2560 rhaas 3602 LBC 0 : deconstruct_array(transarray1,
3603 : INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3604 : &transdatums1, NULL, &ndatums1);
2560 rhaas 3605 UIC 0 : if (ndatums1 != 2)
2560 rhaas 3606 LBC 0 : elog(ERROR, "expected 2-element interval array");
2560 rhaas 3607 ECB :
2560 rhaas 3608 UIC 0 : sum1 = *(DatumGetIntervalP(transdatums1[0]));
2560 rhaas 3609 LBC 0 : N1 = *(DatumGetIntervalP(transdatums1[1]));
3610 :
2560 rhaas 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;
2560 rhaas 3624 ECB :
2560 rhaas 3625 UIC 0 : transdatums1[0] = IntervalPGetDatum(newsum);
2560 rhaas 3626 LBC 0 : transdatums1[1] = IntervalPGetDatum(&N1);
2560 rhaas 3627 ECB :
2560 rhaas 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
3284 tgl 3635 CBC 3 : interval_accum_inv(PG_FUNCTION_ARGS)
3636 : {
3284 tgl 3637 GIC 3 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3284 tgl 3638 CBC 3 : Interval *newval = PG_GETARG_INTERVAL_P(1);
3284 tgl 3639 EUB : Datum *transdatums;
3640 : int ndatums;
3284 tgl 3641 ECB : Interval sumX,
3642 : N;
3643 : Interval *newsum;
3644 : ArrayType *result;
3645 :
3284 tgl 3646 GIC 3 : deconstruct_array(transarray,
1131 tgl 3647 ECB : INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3648 : &transdatums, NULL, &ndatums);
3284 tgl 3649 CBC 3 : if (ndatums != 2)
3284 tgl 3650 LBC 0 : elog(ERROR, "expected 2-element interval array");
3651 :
3284 tgl 3652 CBC 3 : sumX = *(DatumGetIntervalP(transdatums[0]));
3284 tgl 3653 GIC 3 : N = *(DatumGetIntervalP(transdatums[1]));
3654 :
3284 tgl 3655 CBC 3 : newsum = DatumGetIntervalP(DirectFunctionCall2(interval_mi,
3656 : IntervalPGetDatum(&sumX),
3657 : IntervalPGetDatum(newval)));
3284 tgl 3658 GIC 3 : N.time -= 1;
3284 tgl 3659 EUB :
3284 tgl 3660 GIC 3 : transdatums[0] = IntervalPGetDatum(newsum);
3284 tgl 3661 GBC 3 : transdatums[1] = IntervalPGetDatum(&N);
3284 tgl 3662 EUB :
3284 tgl 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
8301 3670 15 : interval_avg(PG_FUNCTION_ARGS)
3671 : {
3672 15 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
3673 : Datum *transdatums;
3674 : int ndatums;
8301 tgl 3675 EUB : Interval sumX,
3676 : N;
3677 :
8301 tgl 3678 GBC 15 : deconstruct_array(transarray,
1131 tgl 3679 EUB : INTERVALOID, sizeof(Interval), false, TYPALIGN_DOUBLE,
3680 : &transdatums, NULL, &ndatums);
8301 tgl 3681 GBC 15 : if (ndatums != 2)
7196 tgl 3682 UBC 0 : elog(ERROR, "expected 2-element interval array");
3683 :
3284 tgl 3684 GBC 15 : sumX = *(DatumGetIntervalP(transdatums[0]));
3284 tgl 3685 GIC 15 : N = *(DatumGetIntervalP(transdatums[1]));
3686 :
3641 peter_e 3687 EUB : /* SQL defines AVG of no values to be NULL */
8301 tgl 3688 GBC 15 : if (N.time == 0)
8301 tgl 3689 GIC 6 : PG_RETURN_NULL();
8301 tgl 3690 EUB :
8301 tgl 3691 GBC 9 : return DirectFunctionCall2(interval_div,
3692 : IntervalPGetDatum(&sumX),
3284 tgl 3693 EUB : Float8GetDatum((double) N.time));
3694 : }
3695 :
8301 3696 :
3697 : /* timestamp_age()
8453 lockhart 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
8339 tgl 3704 UBC 0 : timestamp_age(PG_FUNCTION_ARGS)
3705 : {
8339 tgl 3706 UIC 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
3707 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
8453 lockhart 3708 ECB : Interval *result;
3709 : fsec_t fsec1,
3710 : fsec2;
372 tgl 3711 : struct pg_itm tt,
8453 lockhart 3712 UIC 0 : *tm = &tt;
3713 : struct pg_tm tt1,
3714 0 : *tm1 = &tt1;
3715 : struct pg_tm tt2,
3716 0 : *tm2 = &tt2;
3717 :
8339 tgl 3718 0 : result = (Interval *) palloc(sizeof(Interval));
8453 lockhart 3719 ECB :
6507 bruce 3720 UIC 0 : if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
3721 0 : timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
8453 lockhart 3722 ECB : {
5744 bruce 3723 EUB : /* form the symbolic difference */
372 tgl 3724 UIC 0 : tm->tm_usec = fsec1 - fsec2;
6529 bruce 3725 LBC 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
3726 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
6529 bruce 3727 UIC 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
6529 bruce 3728 LBC 0 : tm->tm_mday = tm1->tm_mday - tm2->tm_mday;
6529 bruce 3729 UIC 0 : tm->tm_mon = tm1->tm_mon - tm2->tm_mon;
3730 0 : tm->tm_year = tm1->tm_year - tm2->tm_year;
8453 lockhart 3731 ECB :
3732 : /* flip sign if necessary... */
8453 lockhart 3733 LBC 0 : if (dt1 < dt2)
8453 lockhart 3734 ECB : {
372 tgl 3735 UIC 0 : tm->tm_usec = -tm->tm_usec;
8453 lockhart 3736 LBC 0 : tm->tm_sec = -tm->tm_sec;
8453 lockhart 3737 UIC 0 : tm->tm_min = -tm->tm_min;
3738 0 : tm->tm_hour = -tm->tm_hour;
8453 lockhart 3739 LBC 0 : tm->tm_mday = -tm->tm_mday;
8453 lockhart 3740 UIC 0 : tm->tm_mon = -tm->tm_mon;
3741 0 : tm->tm_year = -tm->tm_year;
3742 : }
8453 lockhart 3743 ECB :
3744 : /* propagate any negative fields into the next higher field */
372 tgl 3745 LBC 0 : while (tm->tm_usec < 0)
3746 : {
372 tgl 3747 UIC 0 : tm->tm_usec += USECS_PER_SEC;
5744 bruce 3748 0 : tm->tm_sec--;
3749 : }
3750 :
6703 tgl 3751 LBC 0 : while (tm->tm_sec < 0)
3752 : {
6471 bruce 3753 UIC 0 : tm->tm_sec += SECS_PER_MINUTE;
8453 lockhart 3754 LBC 0 : tm->tm_min--;
8453 lockhart 3755 EUB : }
3756 :
6703 tgl 3757 LBC 0 : while (tm->tm_min < 0)
8453 lockhart 3758 ECB : {
6471 bruce 3759 UIC 0 : tm->tm_min += MINS_PER_HOUR;
8453 lockhart 3760 0 : tm->tm_hour--;
8453 lockhart 3761 ECB : }
3762 :
6703 tgl 3763 UIC 0 : while (tm->tm_hour < 0)
8453 lockhart 3764 ECB : {
6471 bruce 3765 UIC 0 : tm->tm_hour += HOURS_PER_DAY;
8453 lockhart 3766 0 : tm->tm_mday--;
3767 : }
3768 :
6703 tgl 3769 0 : while (tm->tm_mday < 0)
3770 : {
8453 lockhart 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
8453 lockhart 3777 EUB : {
8453 lockhart 3778 UIC 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
8453 lockhart 3779 UBC 0 : tm->tm_mon--;
8453 lockhart 3780 EUB : }
3781 : }
3782 :
6703 tgl 3783 UIC 0 : while (tm->tm_mon < 0)
3784 : {
6471 bruce 3785 UBC 0 : tm->tm_mon += MONTHS_PER_YEAR;
8453 lockhart 3786 UIC 0 : tm->tm_year--;
8453 lockhart 3787 EUB : }
3788 :
3789 : /* recover sign if necessary... */
8453 lockhart 3790 UIC 0 : if (dt1 < dt2)
8453 lockhart 3791 EUB : {
372 tgl 3792 UIC 0 : tm->tm_usec = -tm->tm_usec;
8453 lockhart 3793 UBC 0 : tm->tm_sec = -tm->tm_sec;
3794 0 : tm->tm_min = -tm->tm_min;
8453 lockhart 3795 UIC 0 : tm->tm_hour = -tm->tm_hour;
3796 0 : tm->tm_mday = -tm->tm_mday;
8453 lockhart 3797 UBC 0 : tm->tm_mon = -tm->tm_mon;
3798 0 : tm->tm_year = -tm->tm_year;
8453 lockhart 3799 EUB : }
3800 :
372 tgl 3801 UBC 0 : if (itm2interval(tm, result) != 0)
7196 3802 0 : ereport(ERROR,
7196 tgl 3803 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3804 : errmsg("interval out of range")));
3805 : }
8453 lockhart 3806 : else
7196 tgl 3807 UIC 0 : ereport(ERROR,
7196 tgl 3808 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3809 : errmsg("timestamp out of range")));
8453 lockhart 3810 :
8339 tgl 3811 UBC 0 : PG_RETURN_INTERVAL_P(result);
8339 tgl 3812 EUB : }
8453 lockhart 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
7863 3818 : * since year and month are out of context once the arithmetic
3819 : * is done.
8453 3820 : */
8339 tgl 3821 : Datum
7863 lockhart 3822 UIC 0 : timestamptz_age(PG_FUNCTION_ARGS)
3823 : {
7272 tgl 3824 UBC 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
7272 tgl 3825 UIC 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
7863 lockhart 3826 EUB : Interval *result;
372 tgl 3827 : fsec_t fsec1,
3828 : fsec2;
3829 : struct pg_itm tt,
7863 lockhart 3830 UBC 0 : *tm = &tt;
3831 : struct pg_tm tt1,
3832 0 : *tm1 = &tt1;
6797 bruce 3833 EUB : struct pg_tm tt2,
7863 lockhart 3834 UIC 0 : *tm2 = &tt2;
3835 : int tz1;
6703 tgl 3836 EUB : int tz2;
3837 :
7863 lockhart 3838 UBC 0 : result = (Interval *) palloc(sizeof(Interval));
7863 lockhart 3839 EUB :
4042 peter_e 3840 UIC 0 : if (timestamp2tm(dt1, &tz1, tm1, &fsec1, NULL, NULL) == 0 &&
3841 0 : timestamp2tm(dt2, &tz2, tm2, &fsec2, NULL, NULL) == 0)
7863 lockhart 3842 EUB : {
3843 : /* form the symbolic difference */
372 tgl 3844 UBC 0 : tm->tm_usec = fsec1 - fsec2;
6529 bruce 3845 UIC 0 : tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
6529 bruce 3846 UBC 0 : tm->tm_min = tm1->tm_min - tm2->tm_min;
3847 0 : tm->tm_hour = tm1->tm_hour - tm2->tm_hour;
6529 bruce 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;
7863 lockhart 3851 EUB :
3852 : /* flip sign if necessary... */
7863 lockhart 3853 UIC 0 : if (dt1 < dt2)
3854 : {
372 tgl 3855 0 : tm->tm_usec = -tm->tm_usec;
7863 lockhart 3856 UBC 0 : tm->tm_sec = -tm->tm_sec;
7863 lockhart 3857 UIC 0 : tm->tm_min = -tm->tm_min;
7863 lockhart 3858 UBC 0 : tm->tm_hour = -tm->tm_hour;
3859 0 : tm->tm_mday = -tm->tm_mday;
7863 lockhart 3860 UIC 0 : tm->tm_mon = -tm->tm_mon;
3861 0 : tm->tm_year = -tm->tm_year;
3862 : }
7863 lockhart 3863 EUB :
3864 : /* propagate any negative fields into the next higher field */
372 tgl 3865 UBC 0 : while (tm->tm_usec < 0)
5744 bruce 3866 EUB : {
372 tgl 3867 UBC 0 : tm->tm_usec += USECS_PER_SEC;
5744 bruce 3868 0 : tm->tm_sec--;
5744 bruce 3869 EUB : }
3870 :
6703 tgl 3871 UBC 0 : while (tm->tm_sec < 0)
3872 : {
6471 bruce 3873 UIC 0 : tm->tm_sec += SECS_PER_MINUTE;
7863 lockhart 3874 UBC 0 : tm->tm_min--;
7863 lockhart 3875 EUB : }
3876 :
6703 tgl 3877 UIC 0 : while (tm->tm_min < 0)
3878 : {
6471 bruce 3879 0 : tm->tm_min += MINS_PER_HOUR;
7863 lockhart 3880 UBC 0 : tm->tm_hour--;
3881 : }
3882 :
6703 tgl 3883 UIC 0 : while (tm->tm_hour < 0)
7863 lockhart 3884 EUB : {
6471 bruce 3885 UIC 0 : tm->tm_hour += HOURS_PER_DAY;
7863 lockhart 3886 0 : tm->tm_mday--;
3887 : }
3888 :
6703 tgl 3889 0 : while (tm->tm_mday < 0)
3890 : {
7863 lockhart 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--;
7863 lockhart 3895 EUB : }
3896 : else
3897 : {
7863 lockhart 3898 UBC 0 : tm->tm_mday += day_tab[isleap(tm2->tm_year)][tm2->tm_mon - 1];
7863 lockhart 3899 UIC 0 : tm->tm_mon--;
3900 : }
3901 : }
3902 :
6703 tgl 3903 UBC 0 : while (tm->tm_mon < 0)
3904 : {
6471 bruce 3905 0 : tm->tm_mon += MONTHS_PER_YEAR;
7863 lockhart 3906 UIC 0 : tm->tm_year--;
7863 lockhart 3907 EUB : }
3908 :
3909 : /*
3910 : * Note: we deliberately ignore any difference between tz1 and tz2.
6703 tgl 3911 : */
3912 :
7863 lockhart 3913 : /* recover sign if necessary... */
7863 lockhart 3914 UBC 0 : if (dt1 < dt2)
3915 : {
372 tgl 3916 UIC 0 : tm->tm_usec = -tm->tm_usec;
7863 lockhart 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;
7863 lockhart 3923 EUB : }
3924 :
372 tgl 3925 UIC 0 : if (itm2interval(tm, result) != 0)
7196 tgl 3926 UBC 0 : ereport(ERROR,
3927 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 3928 EUB : errmsg("interval out of range")));
7863 lockhart 3929 : }
3930 : else
7196 tgl 3931 UBC 0 : ereport(ERROR,
7196 tgl 3932 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3933 : errmsg("timestamp out of range")));
7863 lockhart 3934 :
7863 lockhart 3935 UIC 0 : PG_RETURN_INTERVAL_P(result);
3936 : }
3937 :
7863 lockhart 3938 EUB :
3939 : /*----------------------------------------------------------
3940 : * Conversion operators.
3941 : *---------------------------------------------------------*/
3942 :
3943 :
746 peter 3944 : /* timestamp_bin()
3945 : * Bin timestamp into specified interval.
3946 : */
3947 : Datum
746 peter 3948 GIC 120 : timestamp_bin(PG_FUNCTION_ARGS)
3949 : {
746 peter 3950 GBC 120 : Interval *stride = PG_GETARG_INTERVAL_P(0);
746 peter 3951 GIC 120 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
746 peter 3952 GBC 120 : Timestamp origin = PG_GETARG_TIMESTAMP(2);
746 peter 3953 EUB : Timestamp result,
3954 : tm_diff,
3955 : stride_usecs,
3956 : tm_delta;
3957 :
746 peter 3958 GBC 120 : if (TIMESTAMP_NOT_FINITE(timestamp))
746 peter 3959 UBC 0 : PG_RETURN_TIMESTAMP(timestamp);
3960 :
746 peter 3961 GIC 120 : if (TIMESTAMP_NOT_FINITE(origin))
746 peter 3962 UBC 0 : ereport(ERROR,
3963 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
746 peter 3964 EUB : errmsg("origin out of range")));
3965 :
746 peter 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;
746 peter 3972 EUB :
620 john.naylor 3973 GIC 114 : if (stride_usecs <= 0)
626 3974 6 : ereport(ERROR,
3975 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
620 john.naylor 3976 EUB : errmsg("stride must be greater than zero")));
3977 :
746 peter 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 : */
729 peter 3985 GIC 108 : if (origin > timestamp && stride_usecs > 1)
3986 36 : tm_delta -= stride_usecs;
729 peter 3987 EUB :
746 peter 3988 GIC 108 : result = origin + tm_delta;
746 peter 3989 EUB :
746 peter 3990 GBC 108 : PG_RETURN_TIMESTAMP(result);
746 peter 3991 EUB : }
3992 :
8453 lockhart 3993 : /* timestamp_trunc()
7863 3994 : * Truncate timestamp to specified units.
8453 3995 : */
3996 : Datum
8339 tgl 3997 GIC 693 : timestamp_trunc(PG_FUNCTION_ARGS)
8453 lockhart 3998 EUB : {
5493 tgl 3999 GBC 693 : text *units = PG_GETARG_TEXT_PP(0);
6385 bruce 4000 GIC 693 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
4001 : Timestamp result;
4002 : int type,
4003 : val;
6911 tgl 4004 EUB : char *lowunits;
4005 : fsec_t fsec;
4006 : struct pg_tm tt,
8453 lockhart 4007 GIC 693 : *tm = &tt;
8453 lockhart 4008 EUB :
6911 tgl 4009 GIC 693 : if (TIMESTAMP_NOT_FINITE(timestamp))
6911 tgl 4010 UIC 0 : PG_RETURN_TIMESTAMP(timestamp);
4011 :
5493 tgl 4012 GIC 693 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4013 693 : VARSIZE_ANY_EXHDR(units),
4014 : false);
4015 :
8453 lockhart 4016 693 : type = DecodeUnits(0, lowunits, &val);
4017 :
7196 tgl 4018 693 : if (type == UNITS)
4019 : {
6471 bruce 4020 693 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
7196 tgl 4021 LBC 0 : ereport(ERROR,
4022 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 4023 ECB : errmsg("timestamp out of range")));
4024 :
7863 lockhart 4025 CBC 693 : switch (val)
4026 : {
6974 bruce 4027 GIC 15 : case DTK_WEEK:
4028 : {
4029 : int woy;
4030 :
6385 bruce 4031 CBC 15 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
6385 bruce 4032 EUB :
4033 : /*
6385 bruce 4034 ECB : * If it is week 52/53 and the month is January, then the
6385 bruce 4035 EUB : * week must belong to the previous year. Also, some
4036 : * December dates belong to the next year.
4037 : */
6385 bruce 4038 GIC 15 : if (woy >= 52 && tm->tm_mon == 1)
6385 bruce 4039 LBC 0 : --tm->tm_year;
6385 bruce 4040 CBC 15 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
6385 bruce 4041 UIC 0 : ++tm->tm_year;
6385 bruce 4042 GIC 15 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4043 15 : tm->tm_hour = 0;
6385 bruce 4044 CBC 15 : tm->tm_min = 0;
6385 bruce 4045 GIC 15 : tm->tm_sec = 0;
6385 bruce 4046 CBC 15 : fsec = 0;
4047 15 : break;
4048 : }
7863 lockhart 4049 GIC 3 : case DTK_MILLENNIUM:
4050 : /* see comments in timestamptz_trunc */
6806 bruce 4051 CBC 3 : if (tm->tm_year > 0)
6797 4052 3 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4053 : else
6797 bruce 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 */
6806 bruce 4058 CBC 6 : if (tm->tm_year > 0)
6797 4059 6 : tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
4060 : else
6797 bruce 4061 LBC 0 : tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
4062 : /* FALL THRU */
7863 lockhart 4063 ECB : case DTK_DECADE:
4064 : /* see comments in timestamptz_trunc */
6806 bruce 4065 GIC 6 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4066 : {
6806 bruce 4067 UIC 0 : if (tm->tm_year > 0)
4068 0 : tm->tm_year = (tm->tm_year / 10) * 10;
4069 : else
6797 bruce 4070 LBC 0 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4071 : }
1061 alvherre 4072 ECB : /* FALL THRU */
7863 lockhart 4073 : case DTK_YEAR:
7863 lockhart 4074 GIC 6 : tm->tm_mon = 1;
4075 : /* FALL THRU */
4076 6 : case DTK_QUARTER:
7197 bruce 4077 6 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
4078 : /* FALL THRU */
7863 lockhart 4079 6 : case DTK_MONTH:
7863 lockhart 4080 CBC 6 : tm->tm_mday = 1;
4081 : /* FALL THRU */
4082 618 : case DTK_DAY:
7863 lockhart 4083 GBC 618 : tm->tm_hour = 0;
4084 : /* FALL THRU */
7863 lockhart 4085 CBC 630 : case DTK_HOUR:
4086 630 : tm->tm_min = 0;
4087 : /* FALL THRU */
7863 lockhart 4088 GIC 642 : case DTK_MINUTE:
7863 lockhart 4089 CBC 642 : tm->tm_sec = 0;
4090 : /* FALL THRU */
4091 654 : case DTK_SECOND:
7863 lockhart 4092 GIC 654 : fsec = 0;
7863 lockhart 4093 CBC 654 : break;
7863 lockhart 4094 EUB :
7863 lockhart 4095 GIC 12 : case DTK_MILLISEC:
6530 bruce 4096 12 : fsec = (fsec / 1000) * 1000;
7863 lockhart 4097 12 : break;
7863 lockhart 4098 ECB :
7863 lockhart 4099 GIC 12 : case DTK_MICROSEC:
7863 lockhart 4100 CBC 12 : break;
4101 :
7863 lockhart 4102 UIC 0 : default:
7196 tgl 4103 0 : ereport(ERROR,
7196 tgl 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 :
7863 lockhart 4110 GIC 693 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
7196 tgl 4111 LBC 0 : ereport(ERROR,
7196 tgl 4112 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 4113 ECB : errmsg("timestamp out of range")));
7863 lockhart 4114 EUB : }
8453 lockhart 4115 ECB : else
4116 : {
7196 tgl 4117 LBC 0 : ereport(ERROR,
7196 tgl 4118 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
461 4119 : errmsg("unit \"%s\" not recognized for type %s",
4120 : lowunits, format_type_be(TIMESTAMPOID))));
4121 : result = 0;
7863 lockhart 4122 : }
4123 :
7863 lockhart 4124 CBC 693 : PG_RETURN_TIMESTAMP(result);
7863 lockhart 4125 ECB : }
4126 :
746 peter 4127 EUB : /* timestamptz_bin()
4128 : * Bin timestamptz into specified interval using specified origin.
4129 : */
4130 : Datum
746 peter 4131 CBC 54 : timestamptz_bin(PG_FUNCTION_ARGS)
746 peter 4132 ECB : {
746 peter 4133 GIC 54 : Interval *stride = PG_GETARG_INTERVAL_P(0);
746 peter 4134 GBC 54 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
733 peter 4135 GIC 54 : TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
4136 : TimestampTz result,
4137 : stride_usecs,
746 peter 4138 ECB : tm_diff,
4139 : tm_delta;
746 peter 4140 EUB :
746 peter 4141 GBC 54 : if (TIMESTAMP_NOT_FINITE(timestamp))
746 peter 4142 UIC 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
746 peter 4143 EUB :
746 peter 4144 GIC 54 : if (TIMESTAMP_NOT_FINITE(origin))
746 peter 4145 UIC 0 : ereport(ERROR,
4146 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
746 peter 4147 ECB : errmsg("origin out of range")));
4148 :
746 peter 4149 CBC 54 : if (stride->month != 0)
4150 6 : ereport(ERROR,
4151 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
746 peter 4152 ECB : errmsg("timestamps cannot be binned into intervals containing months or years")));
4153 :
746 peter 4154 GIC 48 : stride_usecs = stride->day * USECS_PER_DAY + stride->time;
746 peter 4155 ECB :
620 john.naylor 4156 CBC 48 : if (stride_usecs <= 0)
626 john.naylor 4157 GIC 6 : ereport(ERROR,
626 john.naylor 4158 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
620 4159 : errmsg("stride must be greater than zero")));
4160 :
746 peter 4161 CBC 42 : tm_diff = timestamp - origin;
4162 42 : tm_delta = tm_diff - tm_diff % stride_usecs;
4163 :
729 peter 4164 ECB : /*
697 tgl 4165 : * Make sure the returned timestamp is at the start of the bin, even if
4166 : * the origin is in the future.
4167 : */
729 peter 4168 CBC 42 : if (origin > timestamp && stride_usecs > 1)
729 peter 4169 LBC 0 : tm_delta -= stride_usecs;
729 peter 4170 ECB :
746 peter 4171 GIC 42 : result = origin + tm_delta;
746 peter 4172 ECB :
746 peter 4173 CBC 42 : PG_RETURN_TIMESTAMPTZ(result);
4174 : }
746 peter 4175 EUB :
1607 tgl 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
1607 tgl 4183 CBC 654 : timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
7863 lockhart 4184 EUB : {
4185 : TimestampTz result;
4186 : int tz;
4187 : int type,
4188 : val;
6733 tgl 4189 GIC 654 : bool redotz = false;
6911 tgl 4190 EUB : char *lowunits;
4191 : fsec_t fsec;
4192 : struct pg_tm tt,
7863 lockhart 4193 GIC 654 : *tm = &tt;
4194 :
5493 tgl 4195 654 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
4196 654 : VARSIZE_ANY_EXHDR(units),
6911 tgl 4197 ECB : false);
4198 :
6911 tgl 4199 GIC 654 : type = DecodeUnits(0, lowunits, &val);
4200 :
7196 4201 654 : if (type == UNITS)
4202 : {
1607 4203 654 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, tzp) != 0)
7196 tgl 4204 LBC 0 : ereport(ERROR,
4205 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 4206 ECB : errmsg("timestamp out of range")));
4207 :
7863 lockhart 4208 CBC 654 : switch (val)
4209 : {
6974 bruce 4210 GIC 3 : case DTK_WEEK:
4211 : {
4212 : int woy;
4213 :
6385 bruce 4214 CBC 3 : woy = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
6385 bruce 4215 EUB :
4216 : /*
6385 bruce 4217 ECB : * If it is week 52/53 and the month is January, then the
6385 bruce 4218 EUB : * week must belong to the previous year. Also, some
4219 : * December dates belong to the next year.
4220 : */
6385 bruce 4221 GIC 3 : if (woy >= 52 && tm->tm_mon == 1)
6385 bruce 4222 LBC 0 : --tm->tm_year;
6385 bruce 4223 CBC 3 : if (woy <= 1 && tm->tm_mon == MONTHS_PER_YEAR)
6385 bruce 4224 UIC 0 : ++tm->tm_year;
6385 bruce 4225 GIC 3 : isoweek2date(woy, &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
4226 3 : tm->tm_hour = 0;
6385 bruce 4227 CBC 3 : tm->tm_min = 0;
6385 bruce 4228 GIC 3 : tm->tm_sec = 0;
6385 bruce 4229 CBC 3 : fsec = 0;
4230 3 : redotz = true;
6385 bruce 4231 GIC 3 : break;
4232 : }
4233 : /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
7863 lockhart 4234 CBC 3 : case DTK_MILLENNIUM:
6797 bruce 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 : */
6806 bruce 4241 CBC 3 : if (tm->tm_year > 0)
6797 bruce 4242 GBC 3 : tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
4243 : else
6797 bruce 4244 LBC 0 : tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
4245 : /* FALL THRU */
7863 lockhart 4246 ECB : case DTK_CENTURY:
4247 : /* truncating to the century? as above: -100, 1, 101... */
6806 bruce 4248 GIC 15 : if (tm->tm_year > 0)
6797 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 : /*
6385 bruce 4256 ECB : * truncating to the decade? first year of the decade. must
4257 : * not be applied if year was truncated before!
4258 : */
6806 bruce 4259 GIC 24 : if (val != DTK_MILLENNIUM && val != DTK_CENTURY)
4260 : {
4261 9 : if (tm->tm_year > 0)
6806 bruce 4262 CBC 6 : tm->tm_year = (tm->tm_year / 10) * 10;
4263 : else
6797 bruce 4264 GIC 3 : tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
4265 : }
1061 alvherre 4266 ECB : /* FALL THRU */
4267 : case DTK_YEAR:
7863 lockhart 4268 CBC 24 : tm->tm_mon = 1;
1061 alvherre 4269 ECB : /* FALL THRU */
7863 lockhart 4270 GIC 24 : case DTK_QUARTER:
7197 bruce 4271 24 : tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
1061 alvherre 4272 ECB : /* FALL THRU */
7863 lockhart 4273 GIC 24 : case DTK_MONTH:
7863 lockhart 4274 CBC 24 : tm->tm_mday = 1;
4275 : /* FALL THRU */
4276 636 : case DTK_DAY:
7863 lockhart 4277 GBC 636 : tm->tm_hour = 0;
6733 tgl 4278 GIC 636 : redotz = true; /* for all cases >= DAY */
4279 : /* FALL THRU */
7863 lockhart 4280 639 : case DTK_HOUR:
7863 lockhart 4281 CBC 639 : tm->tm_min = 0;
4282 : /* FALL THRU */
4283 642 : case DTK_MINUTE:
7863 lockhart 4284 GIC 642 : tm->tm_sec = 0;
4285 : /* FALL THRU */
4286 645 : case DTK_SECOND:
7863 lockhart 4287 CBC 645 : fsec = 0;
7863 lockhart 4288 GIC 645 : break;
4289 3 : case DTK_MILLISEC:
6470 bruce 4290 3 : fsec = (fsec / 1000) * 1000;
7863 lockhart 4291 3 : break;
4292 3 : case DTK_MICROSEC:
4293 3 : break;
7863 lockhart 4294 ECB :
7863 lockhart 4295 UBC 0 : default:
7196 tgl 4296 LBC 0 : ereport(ERROR,
7196 tgl 4297 EUB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
461 tgl 4298 ECB : errmsg("unit \"%s\" not supported for type %s",
4299 : lowunits, format_type_be(TIMESTAMPTZOID))));
7863 lockhart 4300 : result = 0;
8453 4301 : }
7863 4302 :
6733 tgl 4303 CBC 654 : if (redotz)
1607 4304 639 : tz = DetermineTimeZoneOffset(tm, tzp);
4305 :
7863 lockhart 4306 GIC 654 : if (tm2timestamp(tm, fsec, &tz, &result) != 0)
7196 tgl 4307 LBC 0 : ereport(ERROR,
4308 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4309 : errmsg("timestamp out of range")));
4310 : }
4311 : else
4312 : {
7196 tgl 4313 UIC 0 : ereport(ERROR,
7196 tgl 4314 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
461 4315 : errmsg("unit \"%s\" not recognized for type %s",
4316 : lowunits, format_type_be(TIMESTAMPTZOID))));
7196 tgl 4317 EUB : result = 0;
4318 : }
4319 :
1607 tgl 4320 GIC 654 : return result;
1607 tgl 4321 ECB : }
4322 :
4323 : /* timestamptz_trunc()
4324 : * Truncate timestamptz to specified units in session timezone.
4325 : */
4326 : Datum
1607 tgl 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;
1607 tgl 4332 ECB :
1607 tgl 4333 GIC 627 : if (TIMESTAMP_NOT_FINITE(timestamp))
1607 tgl 4334 LBC 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
1607 tgl 4335 ECB :
1607 tgl 4336 GIC 627 : result = timestamptz_trunc_internal(units, timestamp, session_timezone);
1607 tgl 4337 ECB :
1607 tgl 4338 GIC 627 : PG_RETURN_TIMESTAMPTZ(result);
4339 : }
4340 :
1607 tgl 4341 ECB : /* timestamptz_trunc_zone()
4342 : * Truncate timestamptz to specified units in specified timezone.
4343 : */
4344 : Datum
1607 tgl 4345 GIC 27 : timestamptz_trunc_zone(PG_FUNCTION_ARGS)
1607 tgl 4346 ECB : {
1607 tgl 4347 CBC 27 : text *units = PG_GETARG_TEXT_PP(0);
1607 tgl 4348 GIC 27 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
1607 tgl 4349 CBC 27 : text *zone = PG_GETARG_TEXT_PP(2);
1607 tgl 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 : */
1607 tgl 4357 CBC 27 : if (TIMESTAMP_NOT_FINITE(timestamp))
1607 tgl 4358 LBC 0 : PG_RETURN_TIMESTAMP(timestamp);
1607 tgl 4359 ECB :
4360 : /*
4361 : * Look up the requested timezone.
4362 : */
22 tgl 4363 GNC 27 : tzp = lookup_timezone(zone);
4364 :
1607 tgl 4365 GIC 27 : result = timestamptz_trunc_internal(units, timestamp, tzp);
4366 :
7863 lockhart 4367 27 : PG_RETURN_TIMESTAMPTZ(result);
4368 : }
4369 :
8453 lockhart 4370 ECB : /* interval_trunc()
4371 : * Extract specified field from interval.
4372 : */
8339 tgl 4373 : Datum
8339 tgl 4374 UIC 0 : interval_trunc(PG_FUNCTION_ARGS)
4375 : {
5493 tgl 4376 LBC 0 : text *units = PG_GETARG_TEXT_PP(0);
8339 tgl 4377 UBC 0 : Interval *interval = PG_GETARG_INTERVAL_P(1);
4378 : Interval *result;
8453 lockhart 4379 ECB : int type,
4380 : val;
6911 tgl 4381 : char *lowunits;
4382 : struct pg_itm tt,
8453 lockhart 4383 UIC 0 : *tm = &tt;
4384 :
8339 tgl 4385 0 : result = (Interval *) palloc(sizeof(Interval));
4386 :
5493 4387 0 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5493 tgl 4388 LBC 0 : VARSIZE_ANY_EXHDR(units),
4389 : false);
8453 lockhart 4390 ECB :
8453 lockhart 4391 LBC 0 : type = DecodeUnits(0, lowunits, &val);
8453 lockhart 4392 ECB :
7863 lockhart 4393 UIC 0 : if (type == UNITS)
4394 : {
372 tgl 4395 0 : interval2itm(*interval, tm);
332 4396 0 : switch (val)
4397 : {
4398 0 : case DTK_MILLENNIUM:
4399 : /* caution: C division may have negative remainder */
332 tgl 4400 LBC 0 : tm->tm_year = (tm->tm_year / 1000) * 1000;
332 tgl 4401 EUB : /* FALL THRU */
332 tgl 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 */
332 tgl 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:
332 tgl 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:
332 tgl 4417 UBC 0 : tm->tm_mday = 0;
4418 : /* FALL THRU */
4419 0 : case DTK_DAY:
4420 0 : tm->tm_hour = 0;
4421 : /* FALL THRU */
332 tgl 4422 UIC 0 : case DTK_HOUR:
4423 0 : tm->tm_min = 0;
4424 : /* FALL THRU */
4425 0 : case DTK_MINUTE:
332 tgl 4426 UBC 0 : tm->tm_sec = 0;
4427 : /* FALL THRU */
4428 0 : case DTK_SECOND:
332 tgl 4429 UIC 0 : tm->tm_usec = 0;
332 tgl 4430 UBC 0 : break;
4431 0 : case DTK_MILLISEC:
332 tgl 4432 UIC 0 : tm->tm_usec = (tm->tm_usec / 1000) * 1000;
4433 0 : break;
332 tgl 4434 UBC 0 : case DTK_MICROSEC:
332 tgl 4435 UIC 0 : break;
8453 lockhart 4436 EUB :
332 tgl 4437 UIC 0 : default:
7196 tgl 4438 UBC 0 : ereport(ERROR,
332 tgl 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 :
332 tgl 4445 UBC 0 : if (itm2interval(tm, result) != 0)
332 tgl 4446 UIC 0 : ereport(ERROR,
332 tgl 4447 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4448 : errmsg("interval out of range")));
8453 lockhart 4449 : }
4450 : else
4451 : {
7196 tgl 4452 UIC 0 : ereport(ERROR,
7196 tgl 4453 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
461 4454 : errmsg("unit \"%s\" not recognized for type %s",
4455 : lowunits, format_type_be(INTERVALOID))));
8453 lockhart 4456 : }
4457 :
8339 tgl 4458 UIC 0 : PG_RETURN_INTERVAL_P(result);
8339 tgl 4459 EUB : }
8453 lockhart 4460 :
4461 : /* isoweek2j()
5896 bruce 4462 : *
5624 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.
8258 4465 : */
5896 4466 : int
5896 bruce 4467 GIC 795 : isoweek2j(int year, int week)
8258 bruce 4468 EUB : {
8053 4469 : int day0,
4470 : day4;
4471 :
8258 4472 : /* fourth day of current year */
5896 bruce 4473 GBC 795 : day4 = date2j(year, 1, 4);
8053 bruce 4474 EUB :
8258 4475 : /* day0 == offset to first day of week (Monday) */
7310 tgl 4476 GBC 795 : day0 = j2day(day4 - 1);
8258 bruce 4477 EUB :
5896 bruce 4478 GBC 795 : return ((week - 1) * 7) + (day4 - day0);
4479 : }
5896 bruce 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
5896 bruce 4487 GIC 18 : isoweek2date(int woy, int *year, int *mon, int *mday)
5896 bruce 4488 EUB : {
5896 bruce 4489 GBC 18 : j2date(isoweek2j(*year, woy), year, mon, mday);
5896 bruce 4490 GIC 18 : }
4491 :
4492 : /* isoweekdate2date()
4493 : *
4494 : * Convert an ISO 8601 week date (ISO year, ISO week) into a Gregorian date.
3870 bruce 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
3870 bruce 4500 GIC 12 : isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
5896 bruce 4501 EUB : {
4502 : int jday;
4503 :
5896 bruce 4504 GIC 12 : jday = isoweek2j(*year, isoweek);
4505 : /* convert Gregorian week start (Sunday=1) to ISO week start (Monday=1) */
3870 4506 12 : if (wday > 1)
3870 bruce 4507 UIC 0 : jday += wday - 2;
4508 : else
3870 bruce 4509 GIC 12 : jday += 6;
5896 bruce 4510 CBC 12 : j2date(jday, year, mon, mday);
8258 bruce 4511 GIC 12 : }
4512 :
4513 : /* date2isoweek()
4514 : *
4515 : * Returns ISO week number of year.
8258 bruce 4516 ECB : */
4517 : int
8053 bruce 4518 GIC 1212 : date2isoweek(int year, int mon, int mday)
8258 bruce 4519 ECB : {
4520 : float8 result;
8053 4521 : int day0,
4522 : day4,
4523 : dayn;
4524 :
4525 : /* current day */
8258 bruce 4526 GIC 1212 : dayn = date2j(year, mon, mday);
4527 :
4528 : /* fourth day of current year */
4529 1212 : day4 = date2j(year, 1, 4);
8053 bruce 4530 ECB :
4531 : /* day0 == offset to first day of week (Monday) */
7310 tgl 4532 CBC 1212 : day0 = j2day(day4 - 1);
8053 bruce 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 : */
6530 bruce 4538 GIC 1212 : if (dayn < day4 - day0)
4539 : {
7310 tgl 4540 18 : day4 = date2j(year - 1, 1, 4);
4541 :
4542 : /* day0 == offset to first day of week (Monday) */
7310 tgl 4543 CBC 18 : day0 = j2day(day4 - 1);
4544 : }
4545 :
6530 bruce 4546 GIC 1212 : result = (dayn - (day4 - day0)) / 7 + 1;
8053 bruce 4547 ECB :
4548 : /*
6385 4549 : * Sometimes the last few days in a year will fall into the first week of
6385 bruce 4550 EUB : * the next year, so check for this.
4551 : */
6582 bruce 4552 CBC 1212 : if (result >= 52)
8258 bruce 4553 ECB : {
7310 tgl 4554 CBC 135 : day4 = date2j(year + 1, 1, 4);
4555 :
4556 : /* day0 == offset to first day of week (Monday) */
7310 tgl 4557 GIC 135 : day0 = j2day(day4 - 1);
4558 :
6530 bruce 4559 135 : if (dayn >= day4 - day0)
4560 81 : result = (dayn - (day4 - day0)) / 7 + 1;
8258 bruce 4561 ECB : }
4562 :
8258 bruce 4563 GIC 1212 : return (int) result;
4564 : }
4565 :
4566 :
4567 : /* date2isoyear()
4568 : *
7045 bruce 4569 ECB : * Returns ISO 8601 year number.
4570 : * Note: zero or negative results follow the year-zero-exists convention.
4571 : */
4572 : int
7045 bruce 4573 GIC 7293 : date2isoyear(int year, int mon, int mday)
4574 : {
6797 bruce 4575 ECB : float8 result;
4576 : int day0,
4577 : day4,
4578 : dayn;
4579 :
4580 : /* current day */
7045 bruce 4581 CBC 7293 : dayn = date2j(year, mon, mday);
4582 :
7045 bruce 4583 ECB : /* fourth day of current year */
7045 bruce 4584 GIC 7293 : day4 = date2j(year, 1, 4);
4585 :
7045 bruce 4586 ECB : /* day0 == offset to first day of week (Monday) */
7045 bruce 4587 GIC 7293 : day0 = j2day(day4 - 1);
4588 :
7045 bruce 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 : */
6530 bruce 4593 GIC 7293 : if (dayn < day4 - day0)
4594 : {
7045 bruce 4595 CBC 114 : day4 = date2j(year - 1, 1, 4);
4596 :
7045 bruce 4597 ECB : /* day0 == offset to first day of week (Monday) */
7045 bruce 4598 GIC 114 : day0 = j2day(day4 - 1);
4599 :
7045 bruce 4600 CBC 114 : year--;
4601 : }
7045 bruce 4602 ECB :
6530 bruce 4603 CBC 7293 : result = (dayn - (day4 - day0)) / 7 + 1;
4604 :
4605 : /*
6385 bruce 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 : */
6582 bruce 4609 GIC 7293 : if (result >= 52)
4610 : {
7045 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 :
6530 bruce 4616 CBC 855 : if (dayn >= day4 - day0)
7045 bruce 4617 GIC 513 : year++;
4618 : }
4619 :
4620 7293 : return year;
4621 : }
4622 :
4623 :
5896 bruce 4624 ECB : /* date2isoyearday()
4625 : *
4626 : * Returns the ISO 8601 day-of-year, given a Gregorian year, month and day.
5624 4627 : * Possible return values are 1 through 371 (364 in non-leap years).
4628 : */
4629 : int
5896 bruce 4630 CBC 762 : date2isoyearday(int year, int mon, int mday)
4631 : {
5896 bruce 4632 GIC 762 : return date2j(year, mon, mday) - isoweek2j(date2isoyear(year, mon, mday), 1) + 1;
4633 : }
4634 :
4635 : /*
2635 tgl 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
2635 tgl 4647 GIC 306 : NonFiniteTimestampTzPart(int type, int unit, char *lowunits,
4648 : bool isNegative, bool isTz)
4649 : {
4650 306 : if ((type != UNITS) && (type != RESERV))
461 tgl 4651 UIC 0 : ereport(ERROR,
461 tgl 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 :
2635 tgl 4657 CBC 306 : switch (unit)
4658 : {
2635 tgl 4659 ECB : /* Oscillating units */
2635 tgl 4660 CBC 198 : case DTK_MICROSEC:
4661 : case DTK_MILLISEC:
4662 : case DTK_SECOND:
2635 tgl 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:
2635 tgl 4675 CBC 198 : return 0.0;
4676 :
4677 : /* Monotonically-increasing units */
2635 tgl 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 :
2635 tgl 4690 LBC 0 : default:
461 tgl 4691 UIC 0 : ereport(ERROR,
4692 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
461 tgl 4693 ECB : errmsg("unit \"%s\" not supported for type %s",
461 tgl 4694 EUB : lowunits,
4695 : format_type_be(isTz ? TIMESTAMPTZOID : TIMESTAMPOID))));
4696 : return 0.0; /* keep compiler quiet */
4697 : }
4698 : }
4699 :
733 peter 4700 ECB : /* timestamp_part() and extract_timestamp()
4701 : * Extract specified field from timestamp.
4702 : */
4703 : static Datum
733 peter 4704 GIC 5361 : timestamp_part_common(PG_FUNCTION_ARGS, bool retnumeric)
4705 : {
5493 tgl 4706 5361 : text *units = PG_GETARG_TEXT_PP(0);
6385 bruce 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,
8453 lockhart 4715 5361 : *tm = &tt;
4716 :
5493 tgl 4717 5361 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5493 tgl 4718 CBC 5361 : VARSIZE_ANY_EXHDR(units),
4719 : false);
4720 :
6911 4721 5361 : type = DecodeUnits(0, lowunits, &val);
6911 tgl 4722 GIC 5361 : if (type == UNKNOWN_FIELD)
4723 1857 : type = DecodeSpecial(0, lowunits, &val);
4724 :
2635 4725 5361 : if (TIMESTAMP_NOT_FINITE(timestamp))
4726 : {
733 peter 4727 144 : double r = NonFiniteTimestampTzPart(type, val, lowunits,
733 peter 4728 ECB : TIMESTAMP_IS_NOBEGIN(timestamp),
4729 : false);
4730 :
733 peter 4731 CBC 144 : if (r)
4732 : {
733 peter 4733 GBC 54 : if (retnumeric)
733 peter 4734 EUB : {
733 peter 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
733 peter 4747 CBC 42 : PG_RETURN_FLOAT8(r);
4748 : }
2635 tgl 4749 ECB : else
2635 tgl 4750 CBC 90 : PG_RETURN_NULL();
4751 : }
4752 :
7196 tgl 4753 GIC 5217 : if (type == UNITS)
4754 : {
6471 bruce 4755 4782 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
7196 tgl 4756 UIC 0 : ereport(ERROR,
4757 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 4758 ECB : errmsg("timestamp out of range")));
4759 :
7863 lockhart 4760 CBC 4782 : switch (val)
8453 lockhart 4761 ECB : {
7863 lockhart 4762 GIC 378 : case DTK_MICROSEC:
728 tgl 4763 378 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
7863 lockhart 4764 CBC 378 : break;
7863 lockhart 4765 ECB :
7863 lockhart 4766 CBC 378 : case DTK_MILLISEC:
733 peter 4767 GIC 378 : if (retnumeric)
733 peter 4768 ECB : /*---
4769 : * tm->tm_sec * 1000 + fsec / 1000
4770 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
4771 : */
728 tgl 4772 GIC 189 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
4773 : else
733 peter 4774 CBC 189 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
4775 : break;
7863 lockhart 4776 ECB :
7863 lockhart 4777 GIC 378 : case DTK_SECOND:
733 peter 4778 CBC 378 : if (retnumeric)
733 peter 4779 ECB : /*---
4780 : * tm->tm_sec + fsec / 1'000'000
4781 : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
4782 : */
728 tgl 4783 CBC 189 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
733 peter 4784 ECB : else
733 peter 4785 GIC 189 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
4786 : break;
4787 :
7863 lockhart 4788 189 : case DTK_MINUTE:
733 peter 4789 189 : intresult = tm->tm_min;
7863 lockhart 4790 CBC 189 : break;
4791 :
7863 lockhart 4792 GIC 189 : case DTK_HOUR:
733 peter 4793 CBC 189 : intresult = tm->tm_hour;
7863 lockhart 4794 GIC 189 : break;
4795 :
7863 lockhart 4796 CBC 237 : case DTK_DAY:
733 peter 4797 GIC 237 : intresult = tm->tm_mday;
7863 lockhart 4798 CBC 237 : break;
7863 lockhart 4799 EUB :
7863 lockhart 4800 GIC 237 : case DTK_MONTH:
733 peter 4801 237 : intresult = tm->tm_mon;
7863 lockhart 4802 237 : break;
7863 lockhart 4803 ECB :
7863 lockhart 4804 GIC 237 : case DTK_QUARTER:
733 peter 4805 CBC 237 : intresult = (tm->tm_mon - 1) / 3 + 1;
7863 lockhart 4806 237 : break;
7863 lockhart 4807 ECB :
7863 lockhart 4808 GIC 237 : case DTK_WEEK:
733 peter 4809 CBC 237 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
7863 lockhart 4810 237 : break;
4811 :
7863 lockhart 4812 GIC 237 : case DTK_YEAR:
6949 bruce 4813 237 : if (tm->tm_year > 0)
733 peter 4814 231 : intresult = tm->tm_year;
6949 bruce 4815 ECB : else
4816 : /* there is no year 0, just 1 BC and 1 AD */
733 peter 4817 CBC 6 : intresult = tm->tm_year - 1;
7863 lockhart 4818 GIC 237 : break;
4819 :
7863 lockhart 4820 CBC 237 : case DTK_DECADE:
6797 bruce 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...
6806 4826 : */
6797 bruce 4827 GIC 237 : if (tm->tm_year >= 0)
733 peter 4828 CBC 231 : intresult = tm->tm_year / 10;
4829 : else
733 peter 4830 GIC 6 : intresult = -((8 - (tm->tm_year - 1)) / 10);
7863 lockhart 4831 CBC 237 : break;
7863 lockhart 4832 ECB :
7863 lockhart 4833 CBC 237 : case DTK_CENTURY:
4834 :
6530 bruce 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 : * ----
6938 4840 : */
6938 bruce 4841 CBC 237 : if (tm->tm_year > 0)
733 peter 4842 GIC 231 : intresult = (tm->tm_year + 99) / 100;
6938 bruce 4843 ECB : else
6806 4844 : /* caution: C division may have negative remainder */
733 peter 4845 CBC 6 : intresult = -((99 - (tm->tm_year - 1)) / 100);
7863 lockhart 4846 GIC 237 : break;
7863 lockhart 4847 ECB :
7863 lockhart 4848 CBC 237 : case DTK_MILLENNIUM:
6938 bruce 4849 ECB : /* see comments above. */
6938 bruce 4850 GIC 237 : if (tm->tm_year > 0)
733 peter 4851 CBC 231 : intresult = (tm->tm_year + 999) / 1000;
6938 bruce 4852 ECB : else
733 peter 4853 CBC 6 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
7863 lockhart 4854 GIC 237 : break;
7863 lockhart 4855 ECB :
7771 lockhart 4856 CBC 426 : case DTK_JULIAN:
733 peter 4857 426 : if (retnumeric)
733 peter 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),
728 tgl 4860 ECB : int64_to_numeric(SECS_PER_DAY * INT64CONST(1000000)),
733 peter 4861 : NULL),
4862 : NULL));
4863 : else
733 peter 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 :
5896 bruce 4869 237 : case DTK_ISOYEAR:
733 peter 4870 CBC 237 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
1214 tgl 4871 ECB : /* Adjust BC years */
733 peter 4872 GIC 237 : if (intresult <= 0)
733 peter 4873 CBC 6 : intresult -= 1;
5896 bruce 4874 237 : break;
4875 :
2772 stark 4876 474 : case DTK_DOW:
4877 : case DTK_ISODOW:
733 peter 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;
2772 stark 4881 474 : break;
4882 :
4883 237 : case DTK_DOY:
733 peter 4884 CBC 237 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
4885 237 : - date2j(tm->tm_year, 1, 1) + 1);
2772 stark 4886 GIC 237 : break;
4887 :
7858 lockhart 4888 LBC 0 : case DTK_TZ:
7858 lockhart 4889 ECB : case DTK_TZ_MINUTE:
4890 : case DTK_TZ_HOUR:
7863 4891 : default:
7196 tgl 4892 UIC 0 : ereport(ERROR,
7196 tgl 4893 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
461 4894 : errmsg("unit \"%s\" not supported for type %s",
4895 : lowunits, format_type_be(TIMESTAMPOID))));
733 peter 4896 : intresult = 0;
7863 lockhart 4897 : }
4898 : }
7863 lockhart 4899 CBC 435 : else if (type == RESERV)
7863 lockhart 4900 ECB : {
7863 lockhart 4901 CBC 435 : switch (val)
4902 : {
7863 lockhart 4903 GIC 435 : case DTK_EPOCH:
2580 tgl 4904 435 : epoch = SetEpochTimestamp();
4905 : /* (timestamp - epoch) / 1000000 */
733 peter 4906 435 : if (retnumeric)
733 peter 4907 ECB : {
4908 : Numeric result;
4909 :
733 peter 4910 GIC 195 : if (timestamp < (PG_INT64_MAX + epoch))
4911 192 : result = int64_div_fast_to_numeric(timestamp - epoch, 6);
733 peter 4912 ECB : else
4913 : {
733 peter 4914 GIC 3 : result = numeric_div_opt_error(numeric_sub_opt_error(int64_to_numeric(timestamp),
733 peter 4915 ECB : int64_to_numeric(epoch),
4916 : NULL),
4917 : int64_to_numeric(1000000),
4918 : NULL);
733 peter 4919 CBC 3 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
4920 : NumericGetDatum(result),
733 peter 4921 ECB : Int32GetDatum(6)));
4922 : }
733 peter 4923 CBC 195 : PG_RETURN_NUMERIC(result);
733 peter 4924 ECB : }
4925 : else
4926 : {
4927 : float8 result;
4928 :
4929 : /* try to avoid precision loss in subtraction */
733 peter 4930 GIC 240 : if (timestamp < (PG_INT64_MAX + epoch))
733 peter 4931 GBC 237 : result = (timestamp - epoch) / 1000000.0;
4932 : else
733 peter 4933 GIC 3 : result = ((float8) timestamp - epoch) / 1000000.0;
4934 240 : PG_RETURN_FLOAT8(result);
733 peter 4935 EUB : }
4936 : break;
4937 :
7863 lockhart 4938 UIC 0 : default:
7196 tgl 4939 0 : ereport(ERROR,
4940 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4941 : errmsg("unit \"%s\" not supported for type %s",
461 tgl 4942 ECB : lowunits, format_type_be(TIMESTAMPOID))));
4943 : intresult = 0;
7863 lockhart 4944 : }
4945 : }
4946 : else
4947 : {
7196 tgl 4948 UIC 0 : ereport(ERROR,
7196 tgl 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;
7863 lockhart 4953 : }
8395 4954 :
733 peter 4955 GIC 3600 : if (retnumeric)
4956 189 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
733 peter 4957 ECB : else
733 peter 4958 GIC 3411 : PG_RETURN_FLOAT8(intresult);
4959 : }
4960 :
4961 : Datum
733 peter 4962 CBC 4380 : timestamp_part(PG_FUNCTION_ARGS)
4963 : {
733 peter 4964 GIC 4380 : return timestamp_part_common(fcinfo, false);
4965 : }
8453 lockhart 4966 ECB :
4967 : Datum
733 peter 4968 GIC 981 : extract_timestamp(PG_FUNCTION_ARGS)
4969 : {
4970 981 : return timestamp_part_common(fcinfo, true);
4971 : }
4972 :
733 peter 4973 ECB : /* timestamptz_part() and extract_timestamptz()
7863 lockhart 4974 : * Extract specified field from timestamp with time zone.
4975 : */
733 peter 4976 : static Datum
733 peter 4977 CBC 18692 : timestamptz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
4978 : {
5493 tgl 4979 GIC 18692 : text *units = PG_GETARG_TEXT_PP(0);
7272 4980 18692 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
733 peter 4981 EUB : int64 intresult;
2580 tgl 4982 : Timestamp epoch;
4983 : int tz;
4984 : int type,
4985 : val;
4986 : char *lowunits;
4987 : fsec_t fsec;
4988 : struct pg_tm tt,
7863 lockhart 4989 GIC 18692 : *tm = &tt;
4990 :
5493 tgl 4991 GBC 18692 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5493 tgl 4992 GIC 18692 : VARSIZE_ANY_EXHDR(units),
4993 : false);
4994 :
6911 4995 18692 : type = DecodeUnits(0, lowunits, &val);
4996 18692 : if (type == UNKNOWN_FIELD)
4997 14930 : type = DecodeSpecial(0, lowunits, &val);
6911 tgl 4998 ECB :
2635 tgl 4999 CBC 18692 : if (TIMESTAMP_NOT_FINITE(timestamp))
5000 : {
733 peter 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 : {
733 peter 5009 GIC 12 : if (r < 0)
5010 6 : return DirectFunctionCall3(numeric_in,
733 peter 5011 ECB : CStringGetDatum("-Infinity"),
5012 : ObjectIdGetDatum(InvalidOid),
5013 : Int32GetDatum(-1));
733 peter 5014 GIC 6 : else if (r > 0)
5015 6 : return DirectFunctionCall3(numeric_in,
5016 : CStringGetDatum("Infinity"),
5017 : ObjectIdGetDatum(InvalidOid),
5018 : Int32GetDatum(-1));
5019 : }
733 peter 5020 ECB : else
733 peter 5021 GIC 42 : PG_RETURN_FLOAT8(r);
733 peter 5022 ECB : }
2635 tgl 5023 : else
2635 tgl 5024 GIC 108 : PG_RETURN_NULL();
5025 : }
5026 :
7196 5027 18530 : if (type == UNITS)
5028 : {
4042 peter_e 5029 4800 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
7196 tgl 5030 UIC 0 : ereport(ERROR,
5031 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
7196 tgl 5032 ECB : errmsg("timestamp out of range")));
5033 :
7863 lockhart 5034 CBC 4800 : switch (val)
8453 lockhart 5035 ECB : {
7863 lockhart 5036 GIC 192 : case DTK_TZ:
733 peter 5037 192 : intresult = -tz;
7863 lockhart 5038 CBC 192 : break;
7863 lockhart 5039 ECB :
7863 lockhart 5040 CBC 192 : case DTK_TZ_MINUTE:
733 peter 5041 GIC 192 : intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
7863 lockhart 5042 CBC 192 : break;
5043 :
5044 192 : case DTK_TZ_HOUR:
733 peter 5045 GIC 192 : intresult = -tz / SECS_PER_HOUR;
7863 lockhart 5046 192 : break;
5047 :
7863 lockhart 5048 CBC 384 : case DTK_MICROSEC:
728 tgl 5049 GIC 384 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
7863 lockhart 5050 CBC 384 : break;
5051 :
5052 384 : case DTK_MILLISEC:
733 peter 5053 384 : if (retnumeric)
5054 : /*---
5055 : * tm->tm_sec * 1000 + fsec / 1000
5056 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
733 peter 5057 ECB : */
728 tgl 5058 CBC 192 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
5059 : else
733 peter 5060 GIC 192 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
5061 : break;
5062 :
7863 lockhart 5063 384 : case DTK_SECOND:
733 peter 5064 CBC 384 : if (retnumeric)
5065 : /*---
5066 : * tm->tm_sec + fsec / 1'000'000
733 peter 5067 ECB : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5068 : */
728 tgl 5069 GIC 192 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
733 peter 5070 ECB : else
733 peter 5071 GIC 192 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
7863 lockhart 5072 ECB : break;
7863 lockhart 5073 EUB :
7863 lockhart 5074 GIC 192 : case DTK_MINUTE:
733 peter 5075 192 : intresult = tm->tm_min;
7863 lockhart 5076 192 : break;
7863 lockhart 5077 ECB :
7863 lockhart 5078 GIC 192 : case DTK_HOUR:
733 peter 5079 CBC 192 : intresult = tm->tm_hour;
7863 lockhart 5080 192 : break;
7863 lockhart 5081 ECB :
7863 lockhart 5082 GIC 192 : case DTK_DAY:
733 peter 5083 CBC 192 : intresult = tm->tm_mday;
7863 lockhart 5084 192 : break;
7863 lockhart 5085 ECB :
7863 lockhart 5086 GIC 192 : case DTK_MONTH:
733 peter 5087 CBC 192 : intresult = tm->tm_mon;
7863 lockhart 5088 192 : break;
7863 lockhart 5089 ECB :
7863 lockhart 5090 GIC 192 : case DTK_QUARTER:
733 peter 5091 CBC 192 : intresult = (tm->tm_mon - 1) / 3 + 1;
7863 lockhart 5092 192 : break;
7863 lockhart 5093 ECB :
7863 lockhart 5094 GIC 192 : case DTK_WEEK:
733 peter 5095 CBC 192 : intresult = date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday);
7863 lockhart 5096 192 : break;
5097 :
7863 lockhart 5098 GIC 192 : case DTK_YEAR:
6714 tgl 5099 192 : if (tm->tm_year > 0)
733 peter 5100 189 : intresult = tm->tm_year;
6714 tgl 5101 ECB : else
5102 : /* there is no year 0, just 1 BC and 1 AD */
733 peter 5103 CBC 3 : intresult = tm->tm_year - 1;
7863 lockhart 5104 GIC 192 : break;
5105 :
7863 lockhart 5106 CBC 192 : case DTK_DECADE:
6806 bruce 5107 ECB : /* see comments in timestamp_part */
6797 bruce 5108 GIC 192 : if (tm->tm_year > 0)
733 peter 5109 189 : intresult = tm->tm_year / 10;
5110 : else
5111 3 : intresult = -((8 - (tm->tm_year - 1)) / 10);
7863 lockhart 5112 CBC 192 : break;
5113 :
5114 192 : case DTK_CENTURY:
5115 : /* see comments in timestamp_part */
6806 bruce 5116 GIC 192 : if (tm->tm_year > 0)
733 peter 5117 CBC 189 : intresult = (tm->tm_year + 99) / 100;
6806 bruce 5118 ECB : else
733 peter 5119 CBC 3 : intresult = -((99 - (tm->tm_year - 1)) / 100);
7863 lockhart 5120 GIC 192 : break;
7863 lockhart 5121 ECB :
7863 lockhart 5122 CBC 192 : case DTK_MILLENNIUM:
6806 bruce 5123 ECB : /* see comments in timestamp_part */
6806 bruce 5124 GIC 192 : if (tm->tm_year > 0)
733 peter 5125 CBC 189 : intresult = (tm->tm_year + 999) / 1000;
6806 bruce 5126 ECB : else
733 peter 5127 CBC 3 : intresult = -((999 - (tm->tm_year - 1)) / 1000);
7863 lockhart 5128 GIC 192 : break;
7863 lockhart 5129 ECB :
7771 lockhart 5130 CBC 384 : case DTK_JULIAN:
733 peter 5131 384 : if (retnumeric)
733 peter 5132 GIC 192 : PG_RETURN_NUMERIC(numeric_add_opt_error(int64_to_numeric(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)),
728 tgl 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)),
733 peter 5135 : NULL),
5136 : NULL));
5137 : else
733 peter 5138 CBC 192 : PG_RETURN_FLOAT8(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) +
733 peter 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);
7771 lockhart 5141 : break;
5142 :
5896 bruce 5143 CBC 192 : case DTK_ISOYEAR:
733 peter 5144 GIC 192 : intresult = date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday);
5145 : /* Adjust BC years */
733 peter 5146 CBC 192 : if (intresult <= 0)
5147 3 : intresult -= 1;
5896 bruce 5148 GIC 192 : break;
5896 bruce 5149 ECB :
2772 stark 5150 GIC 384 : case DTK_DOW:
2772 stark 5151 ECB : case DTK_ISODOW:
733 peter 5152 CBC 384 : intresult = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
733 peter 5153 GIC 384 : if (val == DTK_ISODOW && intresult == 0)
733 peter 5154 CBC 9 : intresult = 7;
2772 stark 5155 384 : break;
5156 :
5157 192 : case DTK_DOY:
733 peter 5158 GIC 192 : intresult = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)
733 peter 5159 CBC 192 : - date2j(tm->tm_year, 1, 1) + 1);
2772 stark 5160 192 : break;
5161 :
7863 lockhart 5162 LBC 0 : default:
7196 tgl 5163 0 : ereport(ERROR,
5164 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
461 tgl 5165 ECB : errmsg("unit \"%s\" not supported for type %s",
5166 : lowunits, format_type_be(TIMESTAMPTZOID))));
733 peter 5167 : intresult = 0;
7863 lockhart 5168 : }
5169 : }
7863 lockhart 5170 CBC 13730 : else if (type == RESERV)
7863 lockhart 5171 ECB : {
7863 lockhart 5172 GIC 13730 : switch (val)
7863 lockhart 5173 ECB : {
7863 lockhart 5174 CBC 13730 : case DTK_EPOCH:
2580 tgl 5175 13730 : epoch = SetEpochTimestamp();
5176 : /* (timestamp - epoch) / 1000000 */
733 peter 5177 GIC 13730 : if (retnumeric)
5178 : {
5179 : Numeric result;
5180 :
733 peter 5181 CBC 13535 : if (timestamp < (PG_INT64_MAX + epoch))
733 peter 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),
733 peter 5186 ECB : int64_to_numeric(epoch),
5187 : NULL),
5188 : int64_to_numeric(1000000),
5189 : NULL);
733 peter 5190 CBC 3 : result = DatumGetNumeric(DirectFunctionCall2(numeric_round,
733 peter 5191 ECB : NumericGetDatum(result),
5192 : Int32GetDatum(6)));
5193 : }
733 peter 5194 GIC 13535 : PG_RETURN_NUMERIC(result);
733 peter 5195 ECB : }
2580 tgl 5196 : else
733 peter 5197 : {
5198 : float8 result;
5199 :
5200 : /* try to avoid precision loss in subtraction */
733 peter 5201 CBC 195 : if (timestamp < (PG_INT64_MAX + epoch))
5202 192 : result = (timestamp - epoch) / 1000000.0;
733 peter 5203 ECB : else
733 peter 5204 GIC 3 : result = ((float8) timestamp - epoch) / 1000000.0;
733 peter 5205 GBC 195 : PG_RETURN_FLOAT8(result);
733 peter 5206 EUB : }
5207 : break;
5208 :
7863 lockhart 5209 UIC 0 : default:
7196 tgl 5210 0 : ereport(ERROR,
5211 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5212 : errmsg("unit \"%s\" not supported for type %s",
461 tgl 5213 ECB : lowunits, format_type_be(TIMESTAMPTZOID))));
5214 : intresult = 0;
8453 lockhart 5215 : }
5216 : }
7863 5217 : else
5218 : {
7196 tgl 5219 UIC 0 : ereport(ERROR,
7196 tgl 5220 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5221 : errmsg("unit \"%s\" not recognized for type %s",
5222 : lowunits, format_type_be(TIMESTAMPTZOID))));
5223 :
733 peter 5224 : intresult = 0;
7863 lockhart 5225 : }
5226 :
733 peter 5227 GIC 3648 : if (retnumeric)
733 peter 5228 CBC 192 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
5229 : else
733 peter 5230 GIC 3456 : PG_RETURN_FLOAT8(intresult);
5231 : }
5232 :
733 peter 5233 ECB : Datum
733 peter 5234 GIC 4359 : timestamptz_part(PG_FUNCTION_ARGS)
5235 : {
5236 4359 : return timestamptz_part_common(fcinfo, false);
733 peter 5237 ECB : }
5238 :
5239 : Datum
733 peter 5240 GIC 14333 : extract_timestamptz(PG_FUNCTION_ARGS)
5241 : {
5242 14333 : return timestamptz_part_common(fcinfo, true);
5243 : }
8453 lockhart 5244 ECB :
5245 :
5246 : /* interval_part() and extract_interval()
5247 : * Extract specified field from interval.
5248 : */
5249 : static Datum
733 peter 5250 GIC 546 : interval_part_common(PG_FUNCTION_ARGS, bool retnumeric)
5251 : {
5493 tgl 5252 GBC 546 : text *units = PG_GETARG_TEXT_PP(0);
8339 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,
8453 lockhart 5259 GIC 546 : *tm = &tt;
5260 :
5493 tgl 5261 546 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
5493 tgl 5262 GBC 546 : VARSIZE_ANY_EXHDR(units),
5263 : false);
5264 :
8453 lockhart 5265 GIC 546 : type = DecodeUnits(0, lowunits, &val);
7843 5266 546 : if (type == UNKNOWN_FIELD)
8453 5267 69 : type = DecodeSpecial(0, lowunits, &val);
5268 :
7863 5269 546 : if (type == UNITS)
8453 lockhart 5270 ECB : {
372 tgl 5271 CBC 477 : interval2itm(*interval, tm);
332 tgl 5272 GIC 477 : switch (val)
332 tgl 5273 ECB : {
332 tgl 5274 GIC 60 : case DTK_MICROSEC:
5275 60 : intresult = tm->tm_sec * INT64CONST(1000000) + tm->tm_usec;
5276 60 : break;
8453 lockhart 5277 ECB :
332 tgl 5278 GIC 60 : case DTK_MILLISEC:
332 tgl 5279 CBC 60 : if (retnumeric)
5280 : /*---
5281 : * tm->tm_sec * 1000 + fsec / 1000
5282 : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
332 tgl 5283 ECB : */
332 tgl 5284 GIC 30 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 3));
332 tgl 5285 ECB : else
332 tgl 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
332 tgl 5293 ECB : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
5294 : */
332 tgl 5295 CBC 30 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + tm->tm_usec, 6));
332 tgl 5296 ECB : else
332 tgl 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;
332 tgl 5302 CBC 30 : break;
5303 :
5304 30 : case DTK_HOUR:
5305 30 : intresult = tm->tm_hour;
332 tgl 5306 GIC 30 : break;
5307 :
332 tgl 5308 CBC 30 : case DTK_DAY:
5309 30 : intresult = tm->tm_mday;
5310 30 : break;
5311 :
5312 30 : case DTK_MONTH:
332 tgl 5313 GIC 30 : intresult = tm->tm_mon;
332 tgl 5314 CBC 30 : break;
8453 lockhart 5315 ECB :
332 tgl 5316 GIC 30 : case DTK_QUARTER:
332 tgl 5317 CBC 30 : intresult = (tm->tm_mon / 3) + 1;
5318 30 : break;
8453 lockhart 5319 ECB :
332 tgl 5320 GIC 30 : case DTK_YEAR:
332 tgl 5321 CBC 30 : intresult = tm->tm_year;
5322 30 : break;
5323 :
332 tgl 5324 GIC 42 : case DTK_DECADE:
5325 : /* caution: C division may have negative remainder */
5326 42 : intresult = tm->tm_year / 10;
332 tgl 5327 CBC 42 : break;
5328 :
5329 42 : case DTK_CENTURY:
5330 : /* caution: C division may have negative remainder */
332 tgl 5331 GIC 42 : intresult = tm->tm_year / 100;
332 tgl 5332 CBC 42 : break;
8453 lockhart 5333 ECB :
332 tgl 5334 GIC 30 : case DTK_MILLENNIUM:
5335 : /* caution: C division may have negative remainder */
5336 30 : intresult = tm->tm_year / 1000;
5337 30 : break;
8453 lockhart 5338 ECB :
332 tgl 5339 GIC 3 : default:
332 tgl 5340 CBC 3 : ereport(ERROR,
5341 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5342 : errmsg("unit \"%s\" not supported for type %s",
332 tgl 5343 ECB : lowunits, format_type_be(INTERVALOID))));
5344 : intresult = 0;
5345 : }
5346 : }
6530 bruce 5347 CBC 69 : else if (type == RESERV && val == DTK_EPOCH)
8453 lockhart 5348 ECB : {
733 peter 5349 CBC 66 : if (retnumeric)
5350 : {
733 peter 5351 ECB : Numeric result;
5352 : int64 secs_from_day_month;
5353 : int64 val;
5354 :
355 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 : */
355 peter 5362 GIC 36 : secs_from_day_month = ((int64) (4 * DAYS_PER_YEAR) * (interval->month / MONTHS_PER_YEAR) +
355 peter 5363 CBC 36 : (int64) (4 * DAYS_PER_MONTH) * (interval->month % MONTHS_PER_YEAR) +
5364 36 : (int64) 4 * interval->day) * (SECS_PER_DAY / 4);
733 peter 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 : */
733 peter 5376 GIC 36 : if (!pg_mul_s64_overflow(secs_from_day_month, 1000000, &val) &&
733 peter 5377 CBC 33 : !pg_add_s64_overflow(val, interval->time, &val))
733 peter 5378 GIC 33 : result = int64_div_fast_to_numeric(val, 6);
733 peter 5379 ECB : else
5380 : result =
733 peter 5381 GIC 3 : numeric_add_opt_error(int64_div_fast_to_numeric(interval->time, 6),
733 peter 5382 ECB : int64_to_numeric(secs_from_day_month),
5383 : NULL);
5384 :
733 peter 5385 GIC 36 : PG_RETURN_NUMERIC(result);
5386 : }
5387 : else
5388 : {
5389 : float8 result;
733 peter 5390 ECB :
733 peter 5391 GIC 30 : result = interval->time / 1000000.0;
733 peter 5392 CBC 30 : result += ((double) DAYS_PER_YEAR * SECS_PER_DAY) * (interval->month / MONTHS_PER_YEAR);
733 peter 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 : {
7196 tgl 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))));
733 peter 5405 ECB : intresult = 0;
8453 lockhart 5406 : }
5407 :
733 peter 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 : }
733 peter 5419 ECB :
5420 : Datum
733 peter 5421 CBC 426 : extract_interval(PG_FUNCTION_ARGS)
5422 : {
733 peter 5423 GIC 426 : return interval_part_common(fcinfo, true);
8339 tgl 5424 ECB : }
5425 :
5426 :
5427 : /* timestamp_zone()
6385 bruce 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.
8453 lockhart 5434 : */
8339 tgl 5435 : Datum
8339 tgl 5436 CBC 84 : timestamp_zone(PG_FUNCTION_ARGS)
8453 lockhart 5437 ECB : {
5493 tgl 5438 GIC 84 : text *zone = PG_GETARG_TEXT_PP(0);
6421 tgl 5439 CBC 84 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
5440 : TimestampTz result;
5441 : int tz;
5442 : char tzname[TZ_STRLEN_MAX + 1];
23 tgl 5443 ECB : int type,
5444 : val;
5445 : pg_tz *tzp;
5446 : struct pg_tm tm;
5447 : fsec_t fsec;
5448 :
7863 lockhart 5449 GIC 84 : if (TIMESTAMP_NOT_FINITE(timestamp))
7863 lockhart 5450 LBC 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
7863 lockhart 5451 ECB :
5452 : /*
5453 : * Look up the requested timezone.
6385 bruce 5454 : */
5493 tgl 5455 GIC 84 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5456 :
23 tgl 5457 GNC 84 : type = DecodeTimezoneName(tzname, &val, &tzp);
5458 :
5459 84 : if (type == TZNAME_FIXED_OFFSET)
5460 : {
5461 : /* fixed-offset abbreviation */
3097 tgl 5462 UIC 0 : tz = val;
5463 0 : result = dt2local(timestamp, tz);
5464 : }
23 tgl 5465 GNC 84 : else if (type == TZNAME_DYNTZ)
5466 : {
5467 : /* dynamic-offset abbreviation, resolve using specified time */
3097 tgl 5468 CBC 42 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
3097 tgl 5469 UIC 0 : ereport(ERROR,
3097 tgl 5470 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5471 : errmsg("timestamp out of range")));
3097 tgl 5472 GIC 42 : tz = -DetermineTimeZoneAbbrevOffset(&tm, tzname, tzp);
5389 5473 42 : result = dt2local(timestamp, tz);
5474 : }
5475 : else
5476 : {
5477 : /* full zone name, rotate to that zone */
23 tgl 5478 GNC 42 : if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0)
6421 tgl 5479 UBC 0 : ereport(ERROR,
5480 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5481 : errmsg("timestamp out of range")));
23 tgl 5482 GNC 42 : tz = DetermineTimeZoneOffset(&tm, tzp);
5483 42 : if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
23 tgl 5484 UNC 0 : ereport(ERROR,
5485 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5486 : errmsg("timestamp out of range")));
5487 : }
6469 bruce 5488 ECB :
2580 tgl 5489 GBC 84 : if (!IS_VALID_TIMESTAMP(result))
2580 tgl 5490 UIC 0 : ereport(ERROR,
5491 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2580 tgl 5492 ECB : errmsg("timestamp out of range")));
5493 :
6470 bruce 5494 GIC 84 : PG_RETURN_TIMESTAMPTZ(result);
5495 : }
5496 :
5497 : /* timestamp_izone()
7863 lockhart 5498 ECB : * Encode timestamp type with specified time interval as time zone.
7863 lockhart 5499 EUB : */
5500 : Datum
7863 lockhart 5501 UIC 0 : timestamp_izone(PG_FUNCTION_ARGS)
7863 lockhart 5502 ECB : {
7863 lockhart 5503 LBC 0 : Interval *zone = PG_GETARG_INTERVAL_P(0);
6385 bruce 5504 UBC 0 : Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
5505 : TimestampTz result;
5506 : int tz;
5507 :
7863 lockhart 5508 UIC 0 : if (TIMESTAMP_NOT_FINITE(timestamp))
7863 lockhart 5509 LBC 0 : PG_RETURN_TIMESTAMPTZ(timestamp);
7863 lockhart 5510 EUB :
3720 tgl 5511 UIC 0 : if (zone->month != 0 || zone->day != 0)
7196 5512 0 : ereport(ERROR,
5513 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2118 tgl 5514 ECB : errmsg("interval time zone \"%s\" must not include months or days",
5515 : DatumGetCString(DirectFunctionCall1(interval_out,
5516 : PointerGetDatum(zone))))));
5517 :
6530 bruce 5518 UIC 0 : tz = zone->time / USECS_PER_SEC;
5519 :
7658 lockhart 5520 0 : result = dt2local(timestamp, tz);
7863 lockhart 5521 EUB :
2580 tgl 5522 UIC 0 : if (!IS_VALID_TIMESTAMP(result))
2580 tgl 5523 UBC 0 : ereport(ERROR,
2580 tgl 5524 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5525 : errmsg("timestamp out of range")));
5526 :
7863 lockhart 5527 UIC 0 : PG_RETURN_TIMESTAMPTZ(result);
2118 tgl 5528 EUB : } /* timestamp_izone() */
7863 lockhart 5529 :
5530 : /* TimestampTimestampTzRequiresRewrite()
1493 noah 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
1493 noah 5538 GBC 9 : TimestampTimestampTzRequiresRewrite(void)
5539 : {
1493 noah 5540 EUB : long offset;
5541 :
1493 noah 5542 GBC 9 : if (pg_get_timezone_offset(session_timezone, &offset) && offset == 0)
1386 5543 6 : return false;
1386 noah 5544 GIC 3 : return true;
5545 : }
5546 :
7863 lockhart 5547 EUB : /* timestamp_timestamptz()
5548 : * Convert local timestamp to timestamp at GMT
5549 : */
5550 : Datum
7863 lockhart 5551 GIC 54 : timestamp_timestamptz(PG_FUNCTION_ARGS)
5552 : {
6385 bruce 5553 54 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
5554 :
6957 tgl 5555 54 : PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(timestamp));
5556 : }
5557 :
1292 akorotkov 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.
914 tgl 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
1266 akorotkov 5569 GIC 7956 : timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
5570 : {
7836 bruce 5571 ECB : TimestampTz result;
5572 : struct pg_tm tt,
7863 lockhart 5573 CBC 7956 : *tm = &tt;
5574 : fsec_t fsec;
7863 lockhart 5575 ECB : int tz;
5576 :
914 tgl 5577 GIC 7956 : if (overflow)
5578 7899 : *overflow = 0;
5579 :
7863 lockhart 5580 7956 : if (TIMESTAMP_NOT_FINITE(timestamp))
1292 akorotkov 5581 UIC 0 : return timestamp;
5582 :
5583 : /* We don't expect this to fail, but check it pro forma */
914 tgl 5584 GIC 7956 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
5585 : {
5727 5586 7956 : tz = DetermineTimeZoneOffset(tm, session_timezone);
5587 :
1266 akorotkov 5588 7956 : result = dt2local(timestamp, -tz);
1266 akorotkov 5589 ECB :
1266 akorotkov 5590 GIC 7956 : if (IS_VALID_TIMESTAMP(result))
5591 : {
1292 5592 7950 : return result;
1266 akorotkov 5593 ECB : }
1266 akorotkov 5594 GIC 6 : else if (overflow)
5595 : {
5596 6 : if (result < MIN_TIMESTAMP)
914 tgl 5597 ECB : {
1266 akorotkov 5598 CBC 6 : *overflow = -1;
914 tgl 5599 GIC 6 : TIMESTAMP_NOBEGIN(result);
914 tgl 5600 ECB : }
1266 akorotkov 5601 EUB : else
5602 : {
1266 akorotkov 5603 UIC 0 : *overflow = 1;
914 tgl 5604 LBC 0 : TIMESTAMP_NOEND(result);
5605 : }
914 tgl 5606 CBC 6 : return result;
5607 : }
7863 lockhart 5608 ECB : }
5609 :
1266 akorotkov 5610 LBC 0 : ereport(ERROR,
5611 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1266 akorotkov 5612 ECB : errmsg("timestamp out of range")));
5613 :
1292 5614 : return 0;
5615 : }
5616 :
5617 : /*
914 tgl 5618 : * Promote timestamp to timestamptz, throwing error for overflow.
1292 akorotkov 5619 : */
5620 : static TimestampTz
1292 akorotkov 5621 GIC 57 : timestamp2timestamptz(Timestamp timestamp)
5622 : {
1266 akorotkov 5623 GBC 57 : return timestamp2timestamptz_opt_overflow(timestamp, NULL);
7863 lockhart 5624 EUB : }
5625 :
7863 lockhart 5626 ECB : /* timestamptz_timestamp()
5627 : * Convert timestamp at GMT to local timestamp
5628 : */
5629 : Datum
7863 lockhart 5630 GBC 30992 : timestamptz_timestamp(PG_FUNCTION_ARGS)
5631 : {
7272 tgl 5632 GIC 30992 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
5633 :
2427 5634 30992 : PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
5635 : }
5636 :
5637 : static Timestamp
5638 31025 : timestamptz2timestamp(TimestampTz timestamp)
5639 : {
5640 : Timestamp result;
6797 bruce 5641 ECB : struct pg_tm tt,
7863 lockhart 5642 GIC 31025 : *tm = &tt;
7658 lockhart 5643 ECB : fsec_t fsec;
5644 : int tz;
5645 :
7863 lockhart 5646 GIC 31025 : if (TIMESTAMP_NOT_FINITE(timestamp))
7863 lockhart 5647 UIC 0 : result = timestamp;
5648 : else
5649 : {
4042 peter_e 5650 CBC 31025 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
7196 tgl 5651 UIC 0 : ereport(ERROR,
7196 tgl 5652 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5653 : errmsg("timestamp out of range")));
7863 lockhart 5654 CBC 31025 : if (tm2timestamp(tm, fsec, NULL, &result) != 0)
7196 tgl 5655 UIC 0 : ereport(ERROR,
5656 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5657 : errmsg("timestamp out of range")));
7863 lockhart 5658 ECB : }
2427 tgl 5659 GIC 31025 : return result;
5660 : }
5661 :
7863 lockhart 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
7863 lockhart 5667 GBC 93 : timestamptz_zone(PG_FUNCTION_ARGS)
5668 : {
5493 tgl 5669 GIC 93 : text *zone = PG_GETARG_TEXT_PP(0);
7272 tgl 5670 CBC 93 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
7658 lockhart 5671 EUB : Timestamp result;
5672 : int tz;
5673 : char tzname[TZ_STRLEN_MAX + 1];
23 tgl 5674 : int type,
5675 : val;
5676 : pg_tz *tzp;
5677 :
8339 tgl 5678 CBC 93 : if (TIMESTAMP_NOT_FINITE(timestamp))
6421 tgl 5679 UIC 0 : PG_RETURN_TIMESTAMP(timestamp);
5680 :
5681 : /*
5682 : * Look up the requested timezone.
6385 bruce 5683 ECB : */
5493 tgl 5684 CBC 93 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
5685 :
23 tgl 5686 GNC 93 : type = DecodeTimezoneName(tzname, &val, &tzp);
5687 :
5688 90 : if (type == TZNAME_FIXED_OFFSET)
5689 : {
5690 : /* fixed-offset abbreviation */
3097 tgl 5691 GIC 12 : tz = -val;
5692 12 : result = dt2local(timestamp, tz);
3097 tgl 5693 ECB : }
23 tgl 5694 GNC 78 : else if (type == TZNAME_DYNTZ)
3097 tgl 5695 ECB : {
5696 : /* dynamic-offset abbreviation, resolve using specified time */
5697 : int isdst;
5698 :
3097 tgl 5699 GIC 36 : tz = DetermineTimeZoneAbbrevOffsetTS(timestamp, tzname, tzp, &isdst);
5389 tgl 5700 CBC 36 : result = dt2local(timestamp, tz);
8453 lockhart 5701 ECB : }
5702 : else
6421 tgl 5703 : {
5704 : /* full zone name, rotate from that zone */
5705 : struct pg_tm tm;
5706 : fsec_t fsec;
5707 :
23 tgl 5708 GNC 42 : if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0)
6421 tgl 5709 UIC 0 : ereport(ERROR,
5710 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5711 : errmsg("timestamp out of range")));
23 tgl 5712 GNC 42 : if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
23 tgl 5713 UNC 0 : ereport(ERROR,
5714 : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5715 : errmsg("timestamp out of range")));
8453 lockhart 5716 EUB : }
5717 :
2580 tgl 5718 GIC 90 : if (!IS_VALID_TIMESTAMP(result))
2580 tgl 5719 UIC 0 : ereport(ERROR,
2580 tgl 5720 ECB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5721 : errmsg("timestamp out of range")));
5722 :
7658 lockhart 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.
7658 lockhart 5728 EUB : * Returns a timestamp without time zone.
5729 : */
8189 5730 : Datum
7863 lockhart 5731 UBC 0 : timestamptz_izone(PG_FUNCTION_ARGS)
5732 : {
8189 lockhart 5733 UIC 0 : Interval *zone = PG_GETARG_INTERVAL_P(0);
7272 tgl 5734 0 : TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(1);
7658 lockhart 5735 EUB : Timestamp result;
8189 5736 : int tz;
5737 :
8189 lockhart 5738 UBC 0 : if (TIMESTAMP_NOT_FINITE(timestamp))
6421 tgl 5739 0 : PG_RETURN_TIMESTAMP(timestamp);
5740 :
3720 tgl 5741 UIC 0 : if (zone->month != 0 || zone->day != 0)
7196 5742 0 : ereport(ERROR,
5743 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5744 : errmsg("interval time zone \"%s\" must not include months or days",
2118 tgl 5745 EUB : DatumGetCString(DirectFunctionCall1(interval_out,
5746 : PointerGetDatum(zone))))));
8189 lockhart 5747 :
6530 bruce 5748 UIC 0 : tz = -(zone->time / USECS_PER_SEC);
8189 lockhart 5749 EUB :
7658 lockhart 5750 UBC 0 : result = dt2local(timestamp, tz);
5751 :
2580 tgl 5752 UIC 0 : if (!IS_VALID_TIMESTAMP(result))
5753 0 : ereport(ERROR,
2580 tgl 5754 EUB : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
5755 : errmsg("timestamp out of range")));
5756 :
7658 lockhart 5757 UIC 0 : PG_RETURN_TIMESTAMP(result);
5758 : }
5759 :
5760 : /* generate_series_timestamp()
5453 tgl 5761 ECB : * Generate the set of timestamps from start to finish by step
5762 : */
5763 : Datum
5453 tgl 5764 GIC 120 : generate_series_timestamp(PG_FUNCTION_ARGS)
5765 : {
5766 : FuncCallContext *funcctx;
5767 : generate_series_timestamp_fctx *fctx;
5050 bruce 5768 ECB : Timestamp result;
5769 :
5453 tgl 5770 : /* stuff done only on the first call of the function */
5453 tgl 5771 CBC 120 : if (SRF_IS_FIRSTCALL())
5453 tgl 5772 ECB : {
5050 bruce 5773 GIC 9 : Timestamp start = PG_GETARG_TIMESTAMP(0);
5050 bruce 5774 CBC 9 : Timestamp finish = PG_GETARG_TIMESTAMP(1);
5050 bruce 5775 GIC 9 : Interval *step = PG_GETARG_INTERVAL_P(2);
5776 : MemoryContext oldcontext;
267 peter 5777 GNC 9 : const Interval interval_zero = {0};
5778 :
5779 : /* create a function context for cross-call persistence */
5453 tgl 5780 GIC 9 : funcctx = SRF_FIRSTCALL_INIT();
5781 :
5453 tgl 5782 ECB : /*
5783 : * switch to memory context appropriate for multiple function calls
5784 : */
5453 tgl 5785 GIC 9 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5453 tgl 5786 ECB :
5787 : /* allocate memory for user context */
5788 : fctx = (generate_series_timestamp_fctx *)
5453 tgl 5789 GIC 9 : palloc(sizeof(generate_series_timestamp_fctx));
5790 :
5791 : /*
5453 tgl 5792 ECB : * Use fctx to keep state from call to call. Seed current with the
5793 : * original start value
5794 : */
5453 tgl 5795 GIC 9 : fctx->current = start;
5796 9 : fctx->finish = finish;
5453 tgl 5797 CBC 9 : fctx->step = *step;
5798 :
5453 tgl 5799 ECB : /* Determine sign of the interval */
5453 tgl 5800 GIC 9 : fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5801 :
5802 9 : if (fctx->step_sign == 0)
5453 tgl 5803 CBC 3 : ereport(ERROR,
5453 tgl 5804 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5805 : errmsg("step size cannot equal zero")));
5806 :
5453 tgl 5807 GIC 6 : funcctx->user_fctx = fctx;
5453 tgl 5808 CBC 6 : MemoryContextSwitchTo(oldcontext);
5809 : }
5810 :
5811 : /* stuff done on every call of the function */
5453 tgl 5812 GIC 117 : funcctx = SRF_PERCALL_SETUP();
5453 tgl 5813 ECB :
5814 : /*
5815 : * get the saved state and use current as the result for this iteration
5816 : */
5453 tgl 5817 CBC 117 : fctx = funcctx->user_fctx;
5453 tgl 5818 GBC 117 : result = fctx->current;
5819 :
5453 tgl 5820 GIC 234 : if (fctx->step_sign > 0 ?
5453 tgl 5821 CBC 117 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
5453 tgl 5822 UIC 0 : timestamp_cmp_internal(result, fctx->finish) >= 0)
5823 : {
5824 : /* increment current in preparation for next iteration */
1165 alvherre 5825 GIC 114 : fctx->current = DatumGetTimestamp(DirectFunctionCall2(timestamp_pl_interval,
2118 tgl 5826 ECB : TimestampGetDatum(fctx->current),
5827 : PointerGetDatum(&fctx->step)));
5828 :
5829 : /* do when there is more left to send */
5453 tgl 5830 GIC 114 : SRF_RETURN_NEXT(funcctx, TimestampGetDatum(result));
5453 tgl 5831 ECB : }
5832 : else
5833 : {
5834 : /* do when there is no more left */
5453 tgl 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
22 tgl 5844 GNC 31032 : generate_series_timestamptz_internal(FunctionCallInfo fcinfo)
5845 : {
5846 : FuncCallContext *funcctx;
5847 : generate_series_timestamptz_fctx *fctx;
5453 tgl 5848 ECB : TimestampTz result;
5849 :
5850 : /* stuff done only on the first call of the function */
5453 tgl 5851 CBC 31032 : if (SRF_IS_FIRSTCALL())
5453 tgl 5852 ECB : {
5453 tgl 5853 CBC 22 : TimestampTz start = PG_GETARG_TIMESTAMPTZ(0);
5453 tgl 5854 GIC 22 : TimestampTz finish = PG_GETARG_TIMESTAMPTZ(1);
5050 bruce 5855 CBC 22 : Interval *step = PG_GETARG_INTERVAL_P(2);
22 tgl 5856 GNC 22 : text *zone = (PG_NARGS() == 4) ? PG_GETARG_TEXT_PP(3) : NULL;
5857 : MemoryContext oldcontext;
267 peter 5858 22 : const Interval interval_zero = {0};
5453 tgl 5859 ECB :
5860 : /* create a function context for cross-call persistence */
5453 tgl 5861 GIC 22 : funcctx = SRF_FIRSTCALL_INIT();
5862 :
5863 : /*
5453 tgl 5864 ECB : * switch to memory context appropriate for multiple function calls
5865 : */
5453 tgl 5866 GIC 22 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
5867 :
5453 tgl 5868 ECB : /* allocate memory for user context */
5869 : fctx = (generate_series_timestamptz_fctx *)
5453 tgl 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
5453 tgl 5874 ECB : * original start value
5875 : */
5453 tgl 5876 CBC 22 : fctx->current = start;
5877 22 : fctx->finish = finish;
5453 tgl 5878 GIC 22 : fctx->step = *step;
22 tgl 5879 GNC 22 : fctx->attimezone = zone ? lookup_timezone(zone) : session_timezone;
5880 :
5453 tgl 5881 ECB : /* Determine sign of the interval */
5453 tgl 5882 CBC 22 : fctx->step_sign = interval_cmp_internal(&fctx->step, &interval_zero);
5453 tgl 5883 ECB :
5453 tgl 5884 GIC 22 : if (fctx->step_sign == 0)
5885 3 : ereport(ERROR,
5886 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5453 tgl 5887 ECB : errmsg("step size cannot equal zero")));
5888 :
5453 tgl 5889 GIC 19 : funcctx->user_fctx = fctx;
5890 19 : MemoryContextSwitchTo(oldcontext);
5891 : }
5453 tgl 5892 ECB :
5893 : /* stuff done on every call of the function */
5453 tgl 5894 GIC 31029 : funcctx = SRF_PERCALL_SETUP();
5895 :
5896 : /*
5453 tgl 5897 ECB : * get the saved state and use current as the result for this iteration
5898 : */
5453 tgl 5899 GIC 31029 : fctx = funcctx->user_fctx;
5453 tgl 5900 CBC 31029 : result = fctx->current;
5453 tgl 5901 ECB :
5453 tgl 5902 CBC 62058 : if (fctx->step_sign > 0 ?
5453 tgl 5903 GIC 30987 : timestamp_cmp_internal(result, fctx->finish) <= 0 :
5904 42 : timestamp_cmp_internal(result, fctx->finish) >= 0)
5453 tgl 5905 ECB : {
5906 : /* increment current in preparation for next iteration */
22 tgl 5907 GNC 31013 : fctx->current = timestamptz_pl_interval_internal(fctx->current,
5908 : &fctx->step,
5909 : fctx->attimezone);
5453 tgl 5910 ECB :
5911 : /* do when there is more left to send */
5453 tgl 5912 GIC 31013 : SRF_RETURN_NEXT(funcctx, TimestampTzGetDatum(result));
5913 : }
5914 : else
5453 tgl 5915 ECB : {
5916 : /* do when there is no more left */
5453 tgl 5917 GIC 16 : SRF_RETURN_DONE(funcctx);
5918 : }
5919 : }
5920 :
5921 : Datum
22 tgl 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 : }
|