Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * date.c
4 : : * implements DATE and TIME data types specified in SQL standard
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994-5, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/adt/date.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres.h"
17 : :
18 : : #include <ctype.h>
19 : : #include <limits.h>
20 : : #include <float.h>
21 : : #include <math.h>
22 : : #include <time.h>
23 : :
24 : : #include "access/xact.h"
25 : : #include "catalog/pg_type.h"
26 : : #include "common/hashfn.h"
27 : : #include "common/int.h"
28 : : #include "libpq/pqformat.h"
29 : : #include "miscadmin.h"
30 : : #include "nodes/miscnodes.h"
31 : : #include "nodes/supportnodes.h"
32 : : #include "parser/scansup.h"
33 : : #include "utils/array.h"
34 : : #include "utils/builtins.h"
35 : : #include "utils/date.h"
36 : : #include "utils/datetime.h"
37 : : #include "utils/numeric.h"
38 : : #include "utils/skipsupport.h"
39 : : #include "utils/sortsupport.h"
40 : :
41 : :
42 : : /* common code for timetypmodin and timetztypmodin */
43 : : static int32
1084 michael@paquier.xyz 44 :CBC 28 : anytime_typmodin(bool istz, ArrayType *ta)
45 : : {
46 : : int32 *tl;
47 : : int n;
48 : :
49 : 28 : tl = ArrayGetIntegerTypmods(ta, &n);
50 : :
51 : : /*
52 : : * we're not too tense about good error message here because grammar
53 : : * shouldn't allow wrong number of modifiers for TIME
54 : : */
55 [ - + ]: 28 : if (n != 1)
1084 michael@paquier.xyz 56 [ # # ]:UBC 0 : ereport(ERROR,
57 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
58 : : errmsg("invalid type modifier")));
59 : :
1084 michael@paquier.xyz 60 :CBC 28 : return anytime_typmod_check(istz, tl[0]);
61 : : }
62 : :
63 : : /* exported so parse_expr.c can use it */
64 : : int32
3549 tgl@sss.pgh.pa.us 65 : 300 : anytime_typmod_check(bool istz, int32 typmod)
66 : : {
67 [ - + ]: 300 : if (typmod < 0)
7066 tgl@sss.pgh.pa.us 68 [ # # # # ]:UBC 0 : ereport(ERROR,
69 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
70 : : errmsg("TIME(%d)%s precision must not be negative",
71 : : typmod, (istz ? " WITH TIME ZONE" : ""))));
3549 tgl@sss.pgh.pa.us 72 [ + + ]:CBC 300 : if (typmod > MAX_TIME_PRECISION)
73 : : {
7066 74 [ + - + + ]: 24 : ereport(WARNING,
75 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
76 : : errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
77 : : typmod, (istz ? " WITH TIME ZONE" : ""),
78 : : MAX_TIME_PRECISION)));
79 : 24 : typmod = MAX_TIME_PRECISION;
80 : : }
81 : :
82 : 300 : return typmod;
83 : : }
84 : :
85 : : /* common code for timetypmodout and timetztypmodout */
86 : : static char *
87 : 10 : anytime_typmodout(bool istz, int32 typmod)
88 : : {
89 [ + + ]: 10 : const char *tz = istz ? " with time zone" : " without time zone";
90 : :
91 [ + - ]: 10 : if (typmod >= 0)
4502 peter_e@gmx.net 92 : 10 : return psprintf("(%d)%s", (int) typmod, tz);
93 : : else
1337 drowley@postgresql.o 94 :UBC 0 : return pstrdup(tz);
95 : : }
96 : :
97 : :
98 : : /*****************************************************************************
99 : : * Date ADT
100 : : *****************************************************************************/
101 : :
102 : :
103 : : /* date_in()
104 : : * Given date text string, convert to internal date format.
105 : : */
106 : : Datum
9461 tgl@sss.pgh.pa.us 107 :CBC 11469 : date_in(PG_FUNCTION_ARGS)
108 : : {
109 : 11469 : char *str = PG_GETARG_CSTRING(0);
1243 110 : 11469 : Node *escontext = fcinfo->context;
111 : : DateADT date;
112 : : fsec_t fsec;
113 : : struct pg_tm tt,
10466 bruce@momjian.us 114 : 11469 : *tm = &tt;
115 : : int tzp;
116 : : int dtype;
117 : : int nf;
118 : : int dterr;
119 : : char *field[MAXDATEFIELDS];
120 : : int ftype[MAXDATEFIELDS];
121 : : char workbuf[MAXDATELEN + 1];
122 : : DateTimeErrorExtra extra;
123 : :
7649 neilc@samurai.com 124 : 11469 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
125 : : field, ftype, MAXDATEFIELDS, &nf);
8287 tgl@sss.pgh.pa.us 126 [ + - ]: 11469 : if (dterr == 0)
1243 127 : 11469 : dterr = DecodeDateTime(field, ftype, nf,
128 : : &dtype, tm, &fsec, &tzp, &extra);
8287 129 [ + + ]: 11469 : if (dterr != 0)
130 : : {
1243 131 : 196 : DateTimeParseError(dterr, &extra, str, "date", escontext);
132 : 8 : PG_RETURN_NULL();
133 : : }
134 : :
10467 bruce@momjian.us 135 [ + + + + : 11273 : switch (dtype)
- ]
136 : : {
9575 lockhart@fourpalms.o 137 : 11037 : case DTK_DATE:
138 : 11037 : break;
139 : :
140 : 4 : case DTK_EPOCH:
8985 141 : 4 : GetEpochTime(tm);
9575 142 : 4 : break;
143 : :
6412 tgl@sss.pgh.pa.us 144 : 150 : case DTK_LATE:
145 : 150 : DATE_NOEND(date);
146 : 150 : PG_RETURN_DATEADT(date);
147 : :
148 : 82 : case DTK_EARLY:
149 : 82 : DATE_NOBEGIN(date);
150 : 82 : PG_RETURN_DATEADT(date);
151 : :
10466 bruce@momjian.us 152 :UBC 0 : default:
1243 tgl@sss.pgh.pa.us 153 : 0 : DateTimeParseError(DTERR_BAD_FORMAT, &extra, str, "date", escontext);
154 : 0 : PG_RETURN_NULL();
155 : : }
156 : :
157 : : /* Prevent overflow in Julian-day routines */
7390 tgl@sss.pgh.pa.us 158 [ + + + - :CBC 11041 : if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ - + + +
+ - + ]
1243 159 [ + + ]: 8 : ereturn(escontext, (Datum) 0,
160 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
161 : : errmsg("date out of range: \"%s\"", str)));
162 : :
8432 163 : 11033 : date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
164 : :
165 : : /* Now check for just-out-of-range dates */
3702 166 [ + + + + ]: 11033 : if (!IS_VALID_DATE(date))
1243 167 [ + - ]: 8 : ereturn(escontext, (Datum) 0,
168 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
169 : : errmsg("date out of range: \"%s\"", str)));
170 : :
9461 171 : 11025 : PG_RETURN_DATEADT(date);
172 : : }
173 : :
174 : : /* date_out()
175 : : * Given internal format date, convert to text string.
176 : : */
177 : : Datum
178 : 13823 : date_out(PG_FUNCTION_ARGS)
179 : : {
7507 bruce@momjian.us 180 : 13823 : DateADT date = PG_GETARG_DATEADT(0);
181 : : char *result;
182 : : struct pg_tm tt,
10466 183 : 13823 : *tm = &tt;
184 : : char buf[MAXDATELEN + 1];
185 : :
6412 tgl@sss.pgh.pa.us 186 [ + + + + ]: 13823 : if (DATE_NOT_FINITE(date))
187 : 124 : EncodeSpecialDate(date, buf);
188 : : else
189 : : {
190 : 13699 : j2date(date + POSTGRES_EPOCH_JDATE,
191 : : &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
192 : 13699 : EncodeDateOnly(tm, DateStyle, buf);
193 : : }
194 : :
9461 195 : 13823 : result = pstrdup(buf);
196 : 13823 : PG_RETURN_CSTRING(result);
197 : : }
198 : :
199 : : /*
200 : : * date_recv - converts external binary format to date
201 : : */
202 : : Datum
8394 tgl@sss.pgh.pa.us 203 :UBC 0 : date_recv(PG_FUNCTION_ARGS)
204 : : {
205 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
206 : : DateADT result;
207 : :
6087 heikki.linnakangas@i 208 : 0 : result = (DateADT) pq_getmsgint(buf, sizeof(DateADT));
209 : :
210 : : /* Limit to the same range that date_in() accepts. */
5920 itagaki.takahiro@gma 211 [ # # # # ]: 0 : if (DATE_NOT_FINITE(result))
212 : : /* ok */ ;
3702 tgl@sss.pgh.pa.us 213 [ # # # # ]: 0 : else if (!IS_VALID_DATE(result))
6087 heikki.linnakangas@i 214 [ # # ]: 0 : ereport(ERROR,
215 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
216 : : errmsg("date out of range")));
217 : :
218 : 0 : PG_RETURN_DATEADT(result);
219 : : }
220 : :
221 : : /*
222 : : * date_send - converts date to binary format
223 : : */
224 : : Datum
8394 tgl@sss.pgh.pa.us 225 : 0 : date_send(PG_FUNCTION_ARGS)
226 : : {
7507 bruce@momjian.us 227 : 0 : DateADT date = PG_GETARG_DATEADT(0);
228 : : StringInfoData buf;
229 : :
8394 tgl@sss.pgh.pa.us 230 : 0 : pq_begintypsend(&buf);
3128 andres@anarazel.de 231 : 0 : pq_sendint32(&buf, date);
8394 tgl@sss.pgh.pa.us 232 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
233 : : }
234 : :
235 : : /*
236 : : * make_date - date constructor
237 : : */
238 : : Datum
4552 tgl@sss.pgh.pa.us 239 :CBC 30 : make_date(PG_FUNCTION_ARGS)
240 : : {
241 : : struct pg_tm tm;
242 : : DateADT date;
243 : : int dterr;
3393 alvherre@alvh.no-ip. 244 : 30 : bool bc = false;
245 : :
4552 tgl@sss.pgh.pa.us 246 : 30 : tm.tm_year = PG_GETARG_INT32(0);
247 : 30 : tm.tm_mon = PG_GETARG_INT32(1);
248 : 30 : tm.tm_mday = PG_GETARG_INT32(2);
249 : :
250 : : /* Handle negative years as BC */
3393 alvherre@alvh.no-ip. 251 [ + + ]: 30 : if (tm.tm_year < 0)
252 : : {
512 nathan@postgresql.or 253 : 9 : int year = tm.tm_year;
254 : :
3393 alvherre@alvh.no-ip. 255 : 9 : bc = true;
512 nathan@postgresql.or 256 [ + + ]: 9 : if (pg_neg_s32_overflow(year, &year))
257 [ + - ]: 4 : ereport(ERROR,
258 : : (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
259 : : errmsg("date field value out of range: %d-%02d-%02d",
260 : : tm.tm_year, tm.tm_mon, tm.tm_mday)));
261 : 5 : tm.tm_year = year;
262 : : }
263 : :
3393 alvherre@alvh.no-ip. 264 : 26 : dterr = ValidateDate(DTK_DATE_M, false, false, bc, &tm);
265 : :
4552 tgl@sss.pgh.pa.us 266 [ + + ]: 26 : if (dterr != 0)
267 [ + - ]: 16 : ereport(ERROR,
268 : : (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
269 : : errmsg("date field value out of range: %d-%02d-%02d",
270 : : tm.tm_year, tm.tm_mon, tm.tm_mday)));
271 : :
272 : : /* Prevent overflow in Julian-day routines */
273 [ - + - - : 10 : if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
- - - + -
- - - ]
4552 tgl@sss.pgh.pa.us 274 [ # # ]:UBC 0 : ereport(ERROR,
275 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
276 : : errmsg("date out of range: %d-%02d-%02d",
277 : : tm.tm_year, tm.tm_mon, tm.tm_mday)));
278 : :
4552 tgl@sss.pgh.pa.us 279 :CBC 10 : date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
280 : :
281 : : /* Now check for just-out-of-range dates */
3702 282 [ + - - + ]: 10 : if (!IS_VALID_DATE(date))
3702 tgl@sss.pgh.pa.us 283 [ # # ]:UBC 0 : ereport(ERROR,
284 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
285 : : errmsg("date out of range: %d-%02d-%02d",
286 : : tm.tm_year, tm.tm_mon, tm.tm_mday)));
287 : :
4552 tgl@sss.pgh.pa.us 288 :CBC 10 : PG_RETURN_DATEADT(date);
289 : : }
290 : :
291 : : /*
292 : : * Convert reserved date values to string.
293 : : */
294 : : void
6412 295 : 140 : EncodeSpecialDate(DateADT dt, char *str)
296 : : {
297 [ + + ]: 140 : if (DATE_IS_NOBEGIN(dt))
298 : 70 : strcpy(str, EARLY);
299 [ + - ]: 70 : else if (DATE_IS_NOEND(dt))
300 : 70 : strcpy(str, LATE);
301 : : else /* shouldn't happen */
6412 tgl@sss.pgh.pa.us 302 [ # # ]:UBC 0 : elog(ERROR, "invalid argument for EncodeSpecialDate");
6412 tgl@sss.pgh.pa.us 303 :CBC 140 : }
304 : :
305 : :
306 : : /*
307 : : * GetSQLCurrentDate -- implements CURRENT_DATE
308 : : */
309 : : DateADT
1084 michael@paquier.xyz 310 : 99 : GetSQLCurrentDate(void)
311 : : {
312 : : struct pg_tm tm;
313 : :
314 : : static int cache_year = 0;
315 : : static int cache_mon = 0;
316 : : static int cache_mday = 0;
317 : : static DateADT cache_date;
318 : :
2045 tgl@sss.pgh.pa.us 319 : 99 : GetCurrentDateTime(&tm);
320 : :
321 : : /*
322 : : * date2j involves several integer divisions; moreover, unless our session
323 : : * lives across local midnight, we don't really have to do it more than
324 : : * once. So it seems worth having a separate cache here.
325 : : */
326 [ + + ]: 99 : if (tm.tm_year != cache_year ||
327 [ + - ]: 74 : tm.tm_mon != cache_mon ||
328 [ - + ]: 74 : tm.tm_mday != cache_mday)
329 : : {
330 : 25 : cache_date = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
331 : 25 : cache_year = tm.tm_year;
332 : 25 : cache_mon = tm.tm_mon;
333 : 25 : cache_mday = tm.tm_mday;
334 : : }
335 : :
1084 michael@paquier.xyz 336 : 99 : return cache_date;
337 : : }
338 : :
339 : : /*
340 : : * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
341 : : */
342 : : TimeTzADT *
343 : 16 : GetSQLCurrentTime(int32 typmod)
344 : : {
345 : : TimeTzADT *result;
346 : : struct pg_tm tt,
3549 tgl@sss.pgh.pa.us 347 : 16 : *tm = &tt;
348 : : fsec_t fsec;
349 : : int tz;
350 : :
2045 351 : 16 : GetCurrentTimeUsec(tm, &fsec, &tz);
352 : :
146 michael@paquier.xyz 353 :GNC 16 : result = palloc_object(TimeTzADT);
3549 tgl@sss.pgh.pa.us 354 :CBC 16 : tm2timetz(tm, fsec, tz, result);
355 : 16 : AdjustTimeForTypmod(&(result->time), typmod);
1084 michael@paquier.xyz 356 : 16 : return result;
357 : : }
358 : :
359 : : /*
360 : : * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
361 : : */
362 : : TimeADT
363 : 16 : GetSQLLocalTime(int32 typmod)
364 : : {
365 : : TimeADT result;
366 : : struct pg_tm tt,
3549 tgl@sss.pgh.pa.us 367 : 16 : *tm = &tt;
368 : : fsec_t fsec;
369 : : int tz;
370 : :
2045 371 : 16 : GetCurrentTimeUsec(tm, &fsec, &tz);
372 : :
3549 373 : 16 : tm2time(tm, fsec, &result);
374 : 16 : AdjustTimeForTypmod(&result, typmod);
1084 michael@paquier.xyz 375 : 16 : return result;
376 : : }
377 : :
378 : :
379 : : /*
380 : : * Comparison functions for dates
381 : : */
382 : :
383 : : Datum
9461 tgl@sss.pgh.pa.us 384 : 42403 : date_eq(PG_FUNCTION_ARGS)
385 : : {
386 : 42403 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
387 : 42403 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
388 : :
389 : 42403 : PG_RETURN_BOOL(dateVal1 == dateVal2);
390 : : }
391 : :
392 : : Datum
9461 tgl@sss.pgh.pa.us 393 :GBC 348 : date_ne(PG_FUNCTION_ARGS)
394 : : {
395 : 348 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
396 : 348 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
397 : :
398 : 348 : PG_RETURN_BOOL(dateVal1 != dateVal2);
399 : : }
400 : :
401 : : Datum
9461 tgl@sss.pgh.pa.us 402 :CBC 105413 : date_lt(PG_FUNCTION_ARGS)
403 : : {
404 : 105413 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
405 : 105413 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
406 : :
407 : 105413 : PG_RETURN_BOOL(dateVal1 < dateVal2);
408 : : }
409 : :
410 : : Datum
411 : 4141 : date_le(PG_FUNCTION_ARGS)
412 : : {
413 : 4141 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
414 : 4141 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
415 : :
416 : 4141 : PG_RETURN_BOOL(dateVal1 <= dateVal2);
417 : : }
418 : :
419 : : Datum
420 : 5422 : date_gt(PG_FUNCTION_ARGS)
421 : : {
422 : 5422 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
423 : 5422 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
424 : :
425 : 5422 : PG_RETURN_BOOL(dateVal1 > dateVal2);
426 : : }
427 : :
428 : : Datum
429 : 4824 : date_ge(PG_FUNCTION_ARGS)
430 : : {
431 : 4824 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
432 : 4824 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
433 : :
434 : 4824 : PG_RETURN_BOOL(dateVal1 >= dateVal2);
435 : : }
436 : :
437 : : Datum
438 : 71738 : date_cmp(PG_FUNCTION_ARGS)
439 : : {
440 : 71738 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
441 : 71738 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
442 : :
9575 lockhart@fourpalms.o 443 [ + + ]: 71738 : if (dateVal1 < dateVal2)
9461 tgl@sss.pgh.pa.us 444 : 40959 : PG_RETURN_INT32(-1);
9575 lockhart@fourpalms.o 445 [ + + ]: 30779 : else if (dateVal1 > dateVal2)
9461 tgl@sss.pgh.pa.us 446 : 22706 : PG_RETURN_INT32(1);
447 : 8073 : PG_RETURN_INT32(0);
448 : : }
449 : :
450 : : Datum
5263 451 : 592 : date_sortsupport(PG_FUNCTION_ARGS)
452 : : {
5077 bruce@momjian.us 453 : 592 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
454 : :
1494 john.naylor@postgres 455 : 592 : ssup->comparator = ssup_datum_int32_cmp;
5263 tgl@sss.pgh.pa.us 456 : 592 : PG_RETURN_VOID();
457 : : }
458 : :
459 : : static Datum
396 pg@bowt.ie 460 :UBC 0 : date_decrement(Relation rel, Datum existing, bool *underflow)
461 : : {
462 : 0 : DateADT dexisting = DatumGetDateADT(existing);
463 : :
464 [ # # ]: 0 : if (dexisting == DATEVAL_NOBEGIN)
465 : : {
466 : : /* return value is undefined */
467 : 0 : *underflow = true;
468 : 0 : return (Datum) 0;
469 : : }
470 : :
471 : 0 : *underflow = false;
472 : 0 : return DateADTGetDatum(dexisting - 1);
473 : : }
474 : :
475 : : static Datum
476 : 0 : date_increment(Relation rel, Datum existing, bool *overflow)
477 : : {
478 : 0 : DateADT dexisting = DatumGetDateADT(existing);
479 : :
480 [ # # ]: 0 : if (dexisting == DATEVAL_NOEND)
481 : : {
482 : : /* return value is undefined */
483 : 0 : *overflow = true;
484 : 0 : return (Datum) 0;
485 : : }
486 : :
487 : 0 : *overflow = false;
488 : 0 : return DateADTGetDatum(dexisting + 1);
489 : : }
490 : :
491 : : Datum
492 : 0 : date_skipsupport(PG_FUNCTION_ARGS)
493 : : {
494 : 0 : SkipSupport sksup = (SkipSupport) PG_GETARG_POINTER(0);
495 : :
496 : 0 : sksup->decrement = date_decrement;
497 : 0 : sksup->increment = date_increment;
498 : 0 : sksup->low_elem = DateADTGetDatum(DATEVAL_NOBEGIN);
499 : 0 : sksup->high_elem = DateADTGetDatum(DATEVAL_NOEND);
500 : :
501 : 0 : PG_RETURN_VOID();
502 : : }
503 : :
504 : : Datum
600 peter@eisentraut.org 505 :CBC 152 : hashdate(PG_FUNCTION_ARGS)
506 : : {
507 : 152 : return hash_uint32(PG_GETARG_DATEADT(0));
508 : : }
509 : :
510 : : Datum
600 peter@eisentraut.org 511 :UBC 0 : hashdateextended(PG_FUNCTION_ARGS)
512 : : {
513 : 0 : return hash_uint32_extended(PG_GETARG_DATEADT(0), PG_GETARG_INT64(1));
514 : : }
515 : :
516 : : Datum
6412 tgl@sss.pgh.pa.us 517 :CBC 15 : date_finite(PG_FUNCTION_ARGS)
518 : : {
519 : 15 : DateADT date = PG_GETARG_DATEADT(0);
520 : :
521 [ + + + + ]: 15 : PG_RETURN_BOOL(!DATE_NOT_FINITE(date));
522 : : }
523 : :
524 : : Datum
9461 525 : 8 : date_larger(PG_FUNCTION_ARGS)
526 : : {
527 : 8 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
528 : 8 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
529 : :
530 : 8 : PG_RETURN_DATEADT((dateVal1 > dateVal2) ? dateVal1 : dateVal2);
531 : : }
532 : :
533 : : Datum
9461 tgl@sss.pgh.pa.us 534 :UBC 0 : date_smaller(PG_FUNCTION_ARGS)
535 : : {
536 : 0 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
537 : 0 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
538 : :
539 : 0 : PG_RETURN_DATEADT((dateVal1 < dateVal2) ? dateVal1 : dateVal2);
540 : : }
541 : :
542 : : /* Compute difference between two dates in days.
543 : : */
544 : : Datum
9461 tgl@sss.pgh.pa.us 545 :CBC 978 : date_mi(PG_FUNCTION_ARGS)
546 : : {
547 : 978 : DateADT dateVal1 = PG_GETARG_DATEADT(0);
548 : 978 : DateADT dateVal2 = PG_GETARG_DATEADT(1);
549 : :
6412 550 [ + - + - : 978 : if (DATE_NOT_FINITE(dateVal1) || DATE_NOT_FINITE(dateVal2))
+ - - + ]
6412 tgl@sss.pgh.pa.us 551 [ # # ]:UBC 0 : ereport(ERROR,
552 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
553 : : errmsg("cannot subtract infinite dates")));
554 : :
9461 tgl@sss.pgh.pa.us 555 :CBC 978 : PG_RETURN_INT32((int32) (dateVal1 - dateVal2));
556 : : }
557 : :
558 : : /* Add a number of days to a date, giving a new date.
559 : : * Must handle both positive and negative numbers of days.
560 : : */
561 : : Datum
562 : 1790 : date_pli(PG_FUNCTION_ARGS)
563 : : {
564 : 1790 : DateADT dateVal = PG_GETARG_DATEADT(0);
565 : 1790 : int32 days = PG_GETARG_INT32(1);
566 : : DateADT result;
567 : :
6412 568 [ + - - + ]: 1790 : if (DATE_NOT_FINITE(dateVal))
3240 tgl@sss.pgh.pa.us 569 :UBC 0 : PG_RETURN_DATEADT(dateVal); /* can't change infinity */
570 : :
3702 tgl@sss.pgh.pa.us 571 :CBC 1790 : result = dateVal + days;
572 : :
573 : : /* Check for integer overflow and out-of-allowed-range */
574 [ + - + - : 1790 : if ((days >= 0 ? (result < dateVal) : (result > dateVal)) ||
- - + - ]
575 [ - + ]: 1790 : !IS_VALID_DATE(result))
3702 tgl@sss.pgh.pa.us 576 [ # # ]:UBC 0 : ereport(ERROR,
577 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
578 : : errmsg("date out of range")));
579 : :
3702 tgl@sss.pgh.pa.us 580 :CBC 1790 : PG_RETURN_DATEADT(result);
581 : : }
582 : :
583 : : /* Subtract a number of days from a date, giving a new date.
584 : : */
585 : : Datum
9461 586 : 42 : date_mii(PG_FUNCTION_ARGS)
587 : : {
588 : 42 : DateADT dateVal = PG_GETARG_DATEADT(0);
589 : 42 : int32 days = PG_GETARG_INT32(1);
590 : : DateADT result;
591 : :
6412 592 [ + - - + ]: 42 : if (DATE_NOT_FINITE(dateVal))
3240 tgl@sss.pgh.pa.us 593 :UBC 0 : PG_RETURN_DATEADT(dateVal); /* can't change infinity */
594 : :
3702 tgl@sss.pgh.pa.us 595 :CBC 42 : result = dateVal - days;
596 : :
597 : : /* Check for integer overflow and out-of-allowed-range */
598 [ + - + - : 42 : if ((days >= 0 ? (result > dateVal) : (result < dateVal)) ||
- - + - ]
599 [ - + ]: 42 : !IS_VALID_DATE(result))
3702 tgl@sss.pgh.pa.us 600 [ # # ]:UBC 0 : ereport(ERROR,
601 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
602 : : errmsg("date out of range")));
603 : :
3702 tgl@sss.pgh.pa.us 604 :CBC 42 : PG_RETURN_DATEADT(result);
605 : : }
606 : :
607 : :
608 : : /*
609 : : * Promote date to timestamp.
610 : : *
611 : : * If the date falls out of the valid range for the timestamp type, error
612 : : * handling proceeds based on escontext.
613 : : *
614 : : * If escontext is NULL, we throw an out-of-range error (hard error).
615 : : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
616 : : * upper bound overflow, respectively, and record a soft error.
617 : : *
618 : : * Note: Lower bound overflow is currently not possible, as both date and
619 : : * timestamp datatypes share the same lower boundary: Julian day zero.
620 : : */
621 : : Timestamp
155 michael@paquier.xyz 622 :GNC 3137 : date2timestamp_safe(DateADT dateVal, Node *escontext)
623 : : {
624 : : Timestamp result;
625 : :
6412 tgl@sss.pgh.pa.us 626 [ + + ]:CBC 3137 : if (DATE_IS_NOBEGIN(dateVal))
627 : 54 : TIMESTAMP_NOBEGIN(result);
628 [ + + ]: 3083 : else if (DATE_IS_NOEND(dateVal))
629 : 52 : TIMESTAMP_NOEND(result);
630 : : else
631 : : {
632 : : /*
633 : : * Since dates have the same minimum values as timestamps, only upper
634 : : * boundary need be checked for overflow.
635 : : */
3702 636 [ + + ]: 3031 : if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
637 : : {
155 michael@paquier.xyz 638 :GNC 18 : TIMESTAMP_NOEND(result);
639 [ + + ]: 18 : ereturn(escontext, result,
640 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
641 : : errmsg("date out of range for timestamp")));
642 : : }
643 : :
644 : : /* date is days since 2000, timestamp is microseconds since same... */
3702 tgl@sss.pgh.pa.us 645 :CBC 3013 : result = dateVal * USECS_PER_DAY;
646 : : }
647 : :
6796 648 : 3119 : return result;
649 : : }
650 : :
651 : : /*
652 : : * Promote date to timestamp, throwing error for overflow.
653 : : */
654 : : static TimestampTz
2414 akorotkov@postgresql 655 : 1880 : date2timestamp(DateADT dateVal)
656 : : {
155 michael@paquier.xyz 657 :GNC 1880 : return date2timestamp_safe(dateVal, NULL);
658 : : }
659 : :
660 : : /*
661 : : * Promote date to timestamp with time zone.
662 : : *
663 : : * If the date falls out of the valid range for the timestamp type, error
664 : : * handling proceeds based on escontext.
665 : : *
666 : : * If escontext is NULL, we throw an out-of-range error (hard error).
667 : : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
668 : : * upper bound overflow, respectively, and record a soft error.
669 : : */
670 : : TimestampTz
671 : 356 : date2timestamptz_safe(DateADT dateVal, Node *escontext)
672 : : {
673 : : TimestampTz result;
674 : : struct pg_tm tt,
8116 tgl@sss.pgh.pa.us 675 :CBC 356 : *tm = &tt;
676 : : int tz;
677 : :
6412 678 [ + + ]: 356 : if (DATE_IS_NOBEGIN(dateVal))
6412 tgl@sss.pgh.pa.us 679 :GBC 9 : TIMESTAMP_NOBEGIN(result);
6412 tgl@sss.pgh.pa.us 680 [ + + ]:CBC 347 : else if (DATE_IS_NOEND(dateVal))
6412 tgl@sss.pgh.pa.us 681 :GBC 9 : TIMESTAMP_NOEND(result);
682 : : else
683 : : {
684 : : /*
685 : : * Since dates have the same minimum values as timestamps, only upper
686 : : * boundary need be checked for overflow.
687 : : */
3702 tgl@sss.pgh.pa.us 688 [ + + ]:CBC 338 : if (dateVal >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
689 : : {
155 michael@paquier.xyz 690 :GNC 12 : TIMESTAMP_NOEND(result);
691 [ + + ]: 12 : ereturn(escontext, result,
692 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
693 : : errmsg("date out of range for timestamp")));
694 : : }
695 : :
6412 tgl@sss.pgh.pa.us 696 :CBC 326 : j2date(dateVal + POSTGRES_EPOCH_JDATE,
697 : : &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
698 : 326 : tm->tm_hour = 0;
699 : 326 : tm->tm_min = 0;
700 : 326 : tm->tm_sec = 0;
701 : 326 : tz = DetermineTimeZoneOffset(tm, session_timezone);
702 : :
703 : 326 : result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
704 : :
705 : : /*
706 : : * Since it is possible to go beyond allowed timestamptz range because
707 : : * of time zone, check for allowed timestamp range after adding tz.
708 : : */
3702 709 [ + + - + ]: 326 : if (!IS_VALID_TIMESTAMP(result))
710 : : {
155 michael@paquier.xyz 711 [ + - ]:GNC 12 : if (result < MIN_TIMESTAMP)
712 : 12 : TIMESTAMP_NOBEGIN(result);
713 : : else
155 michael@paquier.xyz 714 :UNC 0 : TIMESTAMP_NOEND(result);
715 : :
155 michael@paquier.xyz 716 [ + + ]:GNC 12 : ereturn(escontext, result,
717 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
718 : : errmsg("date out of range for timestamp")));
719 : : }
720 : : }
721 : :
8116 tgl@sss.pgh.pa.us 722 :CBC 332 : return result;
723 : : }
724 : :
725 : : /*
726 : : * date2timestamp_no_overflow
727 : : *
728 : : * This is chartered to produce a double value that is numerically
729 : : * equivalent to the corresponding Timestamp value, if the date is in the
730 : : * valid range of Timestamps, but in any case not throw an overflow error.
731 : : * We can do this since the numerical range of double is greater than
732 : : * that of non-erroneous timestamps. The results are currently only
733 : : * used for statistical estimation purposes.
734 : : */
735 : : double
5607 tgl@sss.pgh.pa.us 736 :UBC 0 : date2timestamp_no_overflow(DateADT dateVal)
737 : : {
738 : : double result;
739 : :
740 [ # # ]: 0 : if (DATE_IS_NOBEGIN(dateVal))
741 : 0 : result = -DBL_MAX;
742 [ # # ]: 0 : else if (DATE_IS_NOEND(dateVal))
743 : 0 : result = DBL_MAX;
744 : : else
745 : : {
746 : : /* date is days since 2000, timestamp is microseconds since same... */
747 : 0 : result = dateVal * (double) USECS_PER_DAY;
748 : : }
749 : :
750 : 0 : return result;
751 : : }
752 : :
753 : :
754 : : /*
755 : : * Crosstype comparison functions for dates
756 : : */
757 : :
758 : : int32
2036 tgl@sss.pgh.pa.us 759 :CBC 267 : date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
760 : : {
761 : : Timestamp dt1;
155 michael@paquier.xyz 762 :GNC 267 : ErrorSaveContext escontext = {T_ErrorSaveContext};
763 : :
764 : 267 : dt1 = date2timestamp_safe(dateVal, (Node *) &escontext);
765 [ + + ]: 267 : if (escontext.error_occurred)
766 : : {
767 [ - + ]: 14 : Assert(TIMESTAMP_IS_NOEND(dt1)); /* NOBEGIN case cannot occur */
768 : :
769 : : /* dt1 is larger than any finite timestamp, but less than infinity */
2036 tgl@sss.pgh.pa.us 770 [ - + ]:CBC 14 : return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
771 : : }
772 : :
773 : 253 : return timestamp_cmp_internal(dt1, dt2);
774 : : }
775 : :
776 : : Datum
8116 tgl@sss.pgh.pa.us 777 :UBC 0 : date_eq_timestamp(PG_FUNCTION_ARGS)
778 : : {
779 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
780 : 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
781 : :
2036 782 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) == 0);
783 : : }
784 : :
785 : : Datum
8116 786 : 0 : date_ne_timestamp(PG_FUNCTION_ARGS)
787 : : {
788 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
789 : 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
790 : :
2036 791 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) != 0);
792 : : }
793 : :
794 : : Datum
8116 795 : 0 : date_lt_timestamp(PG_FUNCTION_ARGS)
796 : : {
797 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
798 : 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
799 : :
2036 800 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) < 0);
801 : : }
802 : :
803 : : Datum
8116 tgl@sss.pgh.pa.us 804 :CBC 5 : date_gt_timestamp(PG_FUNCTION_ARGS)
805 : : {
806 : 5 : DateADT dateVal = PG_GETARG_DATEADT(0);
807 : 5 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
808 : :
2036 809 : 5 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) > 0);
810 : : }
811 : :
812 : : Datum
8116 tgl@sss.pgh.pa.us 813 :UBC 0 : date_le_timestamp(PG_FUNCTION_ARGS)
814 : : {
815 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
816 : 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
817 : :
2036 818 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) <= 0);
819 : : }
820 : :
821 : : Datum
8116 822 : 0 : date_ge_timestamp(PG_FUNCTION_ARGS)
823 : : {
824 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
825 : 0 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
826 : :
2036 827 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt2) >= 0);
828 : : }
829 : :
830 : : Datum
8116 tgl@sss.pgh.pa.us 831 :GBC 55 : date_cmp_timestamp(PG_FUNCTION_ARGS)
832 : : {
833 : 55 : DateADT dateVal = PG_GETARG_DATEADT(0);
834 : 55 : Timestamp dt2 = PG_GETARG_TIMESTAMP(1);
835 : :
2036 836 : 55 : PG_RETURN_INT32(date_cmp_timestamp_internal(dateVal, dt2));
837 : : }
838 : :
839 : : int32
2036 tgl@sss.pgh.pa.us 840 :CBC 205 : date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
841 : : {
842 : : TimestampTz dt1;
155 michael@paquier.xyz 843 :GNC 205 : ErrorSaveContext escontext = {T_ErrorSaveContext};
844 : :
845 : 205 : dt1 = date2timestamptz_safe(dateVal, (Node *) &escontext);
846 : :
847 [ + + ]: 205 : if (escontext.error_occurred)
848 : : {
849 [ + + ]: 16 : if (TIMESTAMP_IS_NOEND(dt1))
850 : : {
851 : : /* dt1 is larger than any finite timestamp, but less than infinity */
852 [ - + ]: 8 : return TIMESTAMP_IS_NOEND(dt2) ? -1 : +1;
853 : : }
854 [ + - ]: 8 : if (TIMESTAMP_IS_NOBEGIN(dt1))
855 : : {
856 : : /* dt1 is less than any finite timestamp, but more than -infinity */
857 [ - + ]: 8 : return TIMESTAMP_IS_NOBEGIN(dt2) ? +1 : -1;
858 : : }
859 : : }
860 : :
2036 tgl@sss.pgh.pa.us 861 :CBC 189 : return timestamptz_cmp_internal(dt1, dt2);
862 : : }
863 : :
864 : : Datum
8116 tgl@sss.pgh.pa.us 865 :UBC 0 : date_eq_timestamptz(PG_FUNCTION_ARGS)
866 : : {
867 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 868 : 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
869 : :
2036 tgl@sss.pgh.pa.us 870 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) == 0);
871 : : }
872 : :
873 : : Datum
8116 874 : 0 : date_ne_timestamptz(PG_FUNCTION_ARGS)
875 : : {
876 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 877 : 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
878 : :
2036 tgl@sss.pgh.pa.us 879 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) != 0);
880 : : }
881 : :
882 : : Datum
8116 tgl@sss.pgh.pa.us 883 :CBC 4 : date_lt_timestamptz(PG_FUNCTION_ARGS)
884 : : {
885 : 4 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 886 : 4 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
887 : :
2036 tgl@sss.pgh.pa.us 888 : 4 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) < 0);
889 : : }
890 : :
891 : : Datum
8116 892 : 4 : date_gt_timestamptz(PG_FUNCTION_ARGS)
893 : : {
894 : 4 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 895 : 4 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
896 : :
2036 tgl@sss.pgh.pa.us 897 : 4 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) > 0);
898 : : }
899 : :
900 : : Datum
8116 tgl@sss.pgh.pa.us 901 :UBC 0 : date_le_timestamptz(PG_FUNCTION_ARGS)
902 : : {
903 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 904 : 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
905 : :
2036 tgl@sss.pgh.pa.us 906 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) <= 0);
907 : : }
908 : :
909 : : Datum
8116 910 : 0 : date_ge_timestamptz(PG_FUNCTION_ARGS)
911 : : {
912 : 0 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 913 : 0 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
914 : :
2036 tgl@sss.pgh.pa.us 915 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt2) >= 0);
916 : : }
917 : :
918 : : Datum
8116 tgl@sss.pgh.pa.us 919 :GBC 15 : date_cmp_timestamptz(PG_FUNCTION_ARGS)
920 : : {
921 : 15 : DateADT dateVal = PG_GETARG_DATEADT(0);
7919 bruce@momjian.us 922 : 15 : TimestampTz dt2 = PG_GETARG_TIMESTAMPTZ(1);
923 : :
2036 tgl@sss.pgh.pa.us 924 : 15 : PG_RETURN_INT32(date_cmp_timestamptz_internal(dateVal, dt2));
925 : : }
926 : :
927 : : Datum
8116 tgl@sss.pgh.pa.us 928 :UBC 0 : timestamp_eq_date(PG_FUNCTION_ARGS)
929 : : {
930 : 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
931 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
932 : :
2036 933 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) == 0);
934 : : }
935 : :
936 : : Datum
8116 937 : 0 : timestamp_ne_date(PG_FUNCTION_ARGS)
938 : : {
939 : 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
940 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
941 : :
2036 942 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) != 0);
943 : : }
944 : :
945 : : Datum
8116 946 : 0 : timestamp_lt_date(PG_FUNCTION_ARGS)
947 : : {
948 : 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
949 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
950 : :
2036 951 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) > 0);
952 : : }
953 : :
954 : : Datum
8116 tgl@sss.pgh.pa.us 955 :CBC 5 : timestamp_gt_date(PG_FUNCTION_ARGS)
956 : : {
957 : 5 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
958 : 5 : DateADT dateVal = PG_GETARG_DATEADT(1);
959 : :
2036 960 : 5 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) < 0);
961 : : }
962 : :
963 : : Datum
8116 tgl@sss.pgh.pa.us 964 :UBC 0 : timestamp_le_date(PG_FUNCTION_ARGS)
965 : : {
966 : 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
967 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
968 : :
2036 969 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) >= 0);
970 : : }
971 : :
972 : : Datum
8116 973 : 0 : timestamp_ge_date(PG_FUNCTION_ARGS)
974 : : {
975 : 0 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
976 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
977 : :
2036 978 : 0 : PG_RETURN_BOOL(date_cmp_timestamp_internal(dateVal, dt1) <= 0);
979 : : }
980 : :
981 : : Datum
8116 tgl@sss.pgh.pa.us 982 :GBC 78 : timestamp_cmp_date(PG_FUNCTION_ARGS)
983 : : {
984 : 78 : Timestamp dt1 = PG_GETARG_TIMESTAMP(0);
985 : 78 : DateADT dateVal = PG_GETARG_DATEADT(1);
986 : :
2036 987 : 78 : PG_RETURN_INT32(-date_cmp_timestamp_internal(dateVal, dt1));
988 : : }
989 : :
990 : : Datum
8116 tgl@sss.pgh.pa.us 991 :UBC 0 : timestamptz_eq_date(PG_FUNCTION_ARGS)
992 : : {
7919 bruce@momjian.us 993 : 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 994 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
995 : :
2036 996 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) == 0);
997 : : }
998 : :
999 : : Datum
8116 1000 : 0 : timestamptz_ne_date(PG_FUNCTION_ARGS)
1001 : : {
7919 bruce@momjian.us 1002 : 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1003 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
1004 : :
2036 1005 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) != 0);
1006 : : }
1007 : :
1008 : : Datum
8116 1009 : 0 : timestamptz_lt_date(PG_FUNCTION_ARGS)
1010 : : {
7919 bruce@momjian.us 1011 : 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1012 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
1013 : :
2036 1014 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) > 0);
1015 : : }
1016 : :
1017 : : Datum
8116 tgl@sss.pgh.pa.us 1018 :CBC 4 : timestamptz_gt_date(PG_FUNCTION_ARGS)
1019 : : {
7919 bruce@momjian.us 1020 : 4 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1021 : 4 : DateADT dateVal = PG_GETARG_DATEADT(1);
1022 : :
2036 1023 : 4 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) < 0);
1024 : : }
1025 : :
1026 : : Datum
8116 tgl@sss.pgh.pa.us 1027 :UBC 0 : timestamptz_le_date(PG_FUNCTION_ARGS)
1028 : : {
7919 bruce@momjian.us 1029 : 0 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1030 : 0 : DateADT dateVal = PG_GETARG_DATEADT(1);
1031 : :
2036 1032 : 0 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) >= 0);
1033 : : }
1034 : :
1035 : : Datum
8116 tgl@sss.pgh.pa.us 1036 :CBC 4 : timestamptz_ge_date(PG_FUNCTION_ARGS)
1037 : : {
7919 bruce@momjian.us 1038 : 4 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1039 : 4 : DateADT dateVal = PG_GETARG_DATEADT(1);
1040 : :
2036 1041 : 4 : PG_RETURN_BOOL(date_cmp_timestamptz_internal(dateVal, dt1) <= 0);
1042 : : }
1043 : :
1044 : : Datum
8116 tgl@sss.pgh.pa.us 1045 :GBC 78 : timestamptz_cmp_date(PG_FUNCTION_ARGS)
1046 : : {
7919 bruce@momjian.us 1047 : 78 : TimestampTz dt1 = PG_GETARG_TIMESTAMPTZ(0);
8116 tgl@sss.pgh.pa.us 1048 : 78 : DateADT dateVal = PG_GETARG_DATEADT(1);
1049 : :
2036 1050 : 78 : PG_RETURN_INT32(-date_cmp_timestamptz_internal(dateVal, dt1));
1051 : : }
1052 : :
1053 : : /*
1054 : : * in_range support function for date.
1055 : : *
1056 : : * We implement this by promoting the dates to timestamp (without time zone)
1057 : : * and then using the timestamp-and-interval in_range function.
1058 : : */
1059 : : Datum
3009 tgl@sss.pgh.pa.us 1060 :CBC 892 : in_range_date_interval(PG_FUNCTION_ARGS)
1061 : : {
1062 : 892 : DateADT val = PG_GETARG_DATEADT(0);
1063 : 892 : DateADT base = PG_GETARG_DATEADT(1);
1064 : 892 : Interval *offset = PG_GETARG_INTERVAL_P(2);
1065 : 892 : bool sub = PG_GETARG_BOOL(3);
1066 : 892 : bool less = PG_GETARG_BOOL(4);
1067 : : Timestamp valStamp;
1068 : : Timestamp baseStamp;
1069 : :
1070 : : /* XXX we could support out-of-range cases here, perhaps */
1071 : 892 : valStamp = date2timestamp(val);
1072 : 892 : baseStamp = date2timestamp(base);
1073 : :
1074 : 892 : return DirectFunctionCall5(in_range_timestamp_interval,
1075 : : TimestampGetDatum(valStamp),
1076 : : TimestampGetDatum(baseStamp),
1077 : : IntervalPGetDatum(offset),
1078 : : BoolGetDatum(sub),
1079 : : BoolGetDatum(less));
1080 : : }
1081 : :
1082 : :
1083 : : /* extract_date()
1084 : : * Extract specified field from date type.
1085 : : */
1086 : : Datum
1855 peter@eisentraut.org 1087 : 511 : extract_date(PG_FUNCTION_ARGS)
1088 : : {
1089 : 511 : text *units = PG_GETARG_TEXT_PP(0);
1090 : 511 : DateADT date = PG_GETARG_DATEADT(1);
1091 : : int64 intresult;
1092 : : int type,
1093 : : val;
1094 : : char *lowunits;
1095 : : int year,
1096 : : mon,
1097 : : mday;
1098 : :
1099 [ - + ]: 511 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
1100 [ - + - - : 511 : VARSIZE_ANY_EXHDR(units),
- - - - -
+ ]
1101 : : false);
1102 : :
1103 : 511 : type = DecodeUnits(0, lowunits, &val);
1104 [ + + ]: 511 : if (type == UNKNOWN_FIELD)
1105 : 94 : type = DecodeSpecial(0, lowunits, &val);
1106 : :
1107 [ + + + + : 511 : if (DATE_NOT_FINITE(date) && (type == UNITS || type == RESERV))
+ + + + ]
1108 : : {
1109 [ + + - ]: 90 : switch (val)
1110 : : {
1111 : : /* Oscillating units */
1112 : 45 : case DTK_DAY:
1113 : : case DTK_MONTH:
1114 : : case DTK_QUARTER:
1115 : : case DTK_WEEK:
1116 : : case DTK_DOW:
1117 : : case DTK_ISODOW:
1118 : : case DTK_DOY:
1119 : 45 : PG_RETURN_NULL();
1120 : : break;
1121 : :
1122 : : /* Monotonically-increasing units */
1123 : 45 : case DTK_YEAR:
1124 : : case DTK_DECADE:
1125 : : case DTK_CENTURY:
1126 : : case DTK_MILLENNIUM:
1127 : : case DTK_JULIAN:
1128 : : case DTK_ISOYEAR:
1129 : : case DTK_EPOCH:
1130 [ + + ]: 45 : if (DATE_IS_NOBEGIN(date))
1131 : 5 : PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
1132 : : CStringGetDatum("-Infinity"),
1133 : : ObjectIdGetDatum(InvalidOid),
1134 : : Int32GetDatum(-1))));
1135 : : else
1136 : 40 : PG_RETURN_NUMERIC(DatumGetNumeric(DirectFunctionCall3(numeric_in,
1137 : : CStringGetDatum("Infinity"),
1138 : : ObjectIdGetDatum(InvalidOid),
1139 : : Int32GetDatum(-1))));
1855 peter@eisentraut.org 1140 :UBC 0 : default:
1141 [ # # ]: 0 : ereport(ERROR,
1142 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1143 : : errmsg("unit \"%s\" not supported for type %s",
1144 : : lowunits, format_type_be(DATEOID))));
1145 : : }
1146 : : }
1855 peter@eisentraut.org 1147 [ + + ]:CBC 421 : else if (type == UNITS)
1148 : : {
1149 : 407 : j2date(date + POSTGRES_EPOCH_JDATE, &year, &mon, &mday);
1150 : :
1151 [ + + + + : 407 : switch (val)
+ + + + +
+ + + + ]
1152 : : {
1153 : 5 : case DTK_DAY:
1154 : 5 : intresult = mday;
1155 : 5 : break;
1156 : :
1157 : 61 : case DTK_MONTH:
1158 : 61 : intresult = mon;
1159 : 61 : break;
1160 : :
1161 : 5 : case DTK_QUARTER:
1162 : 5 : intresult = (mon - 1) / 3 + 1;
1163 : 5 : break;
1164 : :
1165 : 5 : case DTK_WEEK:
1166 : 5 : intresult = date2isoweek(year, mon, mday);
1167 : 5 : break;
1168 : :
1169 : 126 : case DTK_YEAR:
1170 [ + + ]: 126 : if (year > 0)
1171 : 121 : intresult = year;
1172 : : else
1173 : : /* there is no year 0, just 1 BC and 1 AD */
1174 : 5 : intresult = year - 1;
1175 : 126 : break;
1176 : :
1177 : 40 : case DTK_DECADE:
1178 : : /* see comments in timestamp_part */
1179 [ + + ]: 40 : if (year >= 0)
1180 : 25 : intresult = year / 10;
1181 : : else
1182 : 15 : intresult = -((8 - (year - 1)) / 10);
1183 : 40 : break;
1184 : :
1185 : 54 : case DTK_CENTURY:
1186 : : /* see comments in timestamp_part */
1187 [ + + ]: 54 : if (year > 0)
1188 : 39 : intresult = (year + 99) / 100;
1189 : : else
1190 : 15 : intresult = -((99 - (year - 1)) / 100);
1191 : 54 : break;
1192 : :
1193 : 39 : case DTK_MILLENNIUM:
1194 : : /* see comments in timestamp_part */
1195 [ + + ]: 39 : if (year > 0)
1196 : 34 : intresult = (year + 999) / 1000;
1197 : : else
1198 : 5 : intresult = -((999 - (year - 1)) / 1000);
1199 : 39 : break;
1200 : :
1201 : 5 : case DTK_JULIAN:
1202 : 5 : intresult = date + POSTGRES_EPOCH_JDATE;
1203 : 5 : break;
1204 : :
1205 : 10 : case DTK_ISOYEAR:
1206 : 10 : intresult = date2isoyear(year, mon, mday);
1207 : : /* Adjust BC years */
1208 [ + + ]: 10 : if (intresult <= 0)
1209 : 5 : intresult -= 1;
1210 : 10 : break;
1211 : :
1212 : 20 : case DTK_DOW:
1213 : : case DTK_ISODOW:
1214 : 20 : intresult = j2day(date + POSTGRES_EPOCH_JDATE);
1215 [ + + + + ]: 20 : if (val == DTK_ISODOW && intresult == 0)
1216 : 5 : intresult = 7;
1217 : 20 : break;
1218 : :
1219 : 5 : case DTK_DOY:
1220 : 5 : intresult = date2j(year, mon, mday) - date2j(year, 1, 1) + 1;
1221 : 5 : break;
1222 : :
1223 : 32 : default:
1224 [ + - ]: 32 : ereport(ERROR,
1225 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1226 : : errmsg("unit \"%s\" not supported for type %s",
1227 : : lowunits, format_type_be(DATEOID))));
1228 : : intresult = 0;
1229 : : }
1230 : : }
1231 [ + + ]: 14 : else if (type == RESERV)
1232 : : {
1233 [ + - ]: 10 : switch (val)
1234 : : {
1235 : 10 : case DTK_EPOCH:
1236 : 10 : intresult = ((int64) date + POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY;
1237 : 10 : break;
1238 : :
1855 peter@eisentraut.org 1239 :UBC 0 : default:
1240 [ # # ]: 0 : ereport(ERROR,
1241 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1242 : : errmsg("unit \"%s\" not supported for type %s",
1243 : : lowunits, format_type_be(DATEOID))));
1244 : : intresult = 0;
1245 : : }
1246 : : }
1247 : : else
1248 : : {
1855 peter@eisentraut.org 1249 [ + - ]:CBC 4 : ereport(ERROR,
1250 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1251 : : errmsg("unit \"%s\" not recognized for type %s",
1252 : : lowunits, format_type_be(DATEOID))));
1253 : : intresult = 0;
1254 : : }
1255 : :
1256 : 385 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
1257 : : }
1258 : :
1259 : :
1260 : : /* Add an interval to a date, giving a new date.
1261 : : * Must handle both positive and negative intervals.
1262 : : *
1263 : : * We implement this by promoting the date to timestamp (without time zone)
1264 : : * and then using the timestamp plus interval function.
1265 : : */
1266 : : Datum
8780 lockhart@fourpalms.o 1267 : 33 : date_pl_interval(PG_FUNCTION_ARGS)
1268 : : {
1269 : 33 : DateADT dateVal = PG_GETARG_DATEADT(0);
1270 : 33 : Interval *span = PG_GETARG_INTERVAL_P(1);
1271 : : Timestamp dateStamp;
1272 : :
8116 tgl@sss.pgh.pa.us 1273 : 33 : dateStamp = date2timestamp(dateVal);
1274 : :
1275 : 33 : return DirectFunctionCall2(timestamp_pl_interval,
1276 : : TimestampGetDatum(dateStamp),
1277 : : PointerGetDatum(span));
1278 : : }
1279 : :
1280 : : /* Subtract an interval from a date, giving a new date.
1281 : : * Must handle both positive and negative intervals.
1282 : : *
1283 : : * We implement this by promoting the date to timestamp (without time zone)
1284 : : * and then using the timestamp minus interval function.
1285 : : */
1286 : : Datum
8780 lockhart@fourpalms.o 1287 : 38 : date_mi_interval(PG_FUNCTION_ARGS)
1288 : : {
1289 : 38 : DateADT dateVal = PG_GETARG_DATEADT(0);
1290 : 38 : Interval *span = PG_GETARG_INTERVAL_P(1);
1291 : : Timestamp dateStamp;
1292 : :
8116 tgl@sss.pgh.pa.us 1293 : 38 : dateStamp = date2timestamp(dateVal);
1294 : :
1295 : 38 : return DirectFunctionCall2(timestamp_mi_interval,
1296 : : TimestampGetDatum(dateStamp),
1297 : : PointerGetDatum(span));
1298 : : }
1299 : :
1300 : : /* date_timestamp()
1301 : : * Convert date to timestamp data type.
1302 : : */
1303 : : Datum
9461 1304 : 972 : date_timestamp(PG_FUNCTION_ARGS)
1305 : : {
1306 : 972 : DateADT dateVal = PG_GETARG_DATEADT(0);
1307 : : Timestamp result;
1308 : :
42 peter@eisentraut.org 1309 :GNC 972 : result = date2timestamp_safe(dateVal, fcinfo->context);
1310 [ - + - - : 968 : if (SOFT_ERROR_OCCURRED(fcinfo->context))
- - ]
42 peter@eisentraut.org 1311 :UNC 0 : PG_RETURN_NULL();
1312 : :
8985 lockhart@fourpalms.o 1313 :CBC 968 : PG_RETURN_TIMESTAMP(result);
1314 : : }
1315 : :
1316 : : /* timestamp_date()
1317 : : * Convert timestamp to date data type.
1318 : : */
1319 : : Datum
1320 : 2022 : timestamp_date(PG_FUNCTION_ARGS)
1321 : : {
7507 bruce@momjian.us 1322 : 2022 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1323 : : DateADT result;
1324 : :
42 peter@eisentraut.org 1325 :GNC 2022 : result = timestamp2date_safe(timestamp, fcinfo->context);
1326 [ - + - - : 2022 : if (SOFT_ERROR_OCCURRED(fcinfo->context))
- - ]
42 peter@eisentraut.org 1327 :UNC 0 : PG_RETURN_NULL();
1328 : :
306 tgl@sss.pgh.pa.us 1329 :GNC 2022 : PG_RETURN_DATEADT(result);
1330 : : }
1331 : :
1332 : : /*
1333 : : * Convert timestamp to date.
1334 : : *
1335 : : * If the timestamp falls out of the valid range for the date type, error
1336 : : * handling proceeds based on escontext.
1337 : : *
1338 : : * If escontext is NULL, we throw an out-of-range error (hard error).
1339 : : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
1340 : : * upper bound overflow, respectively, and record a soft error.
1341 : : *
1342 : : * Note: given the ranges of the types, overflow is only possible at
1343 : : * the lower bound of the range, but we don't assume that in this code.
1344 : : */
1345 : : DateADT
155 michael@paquier.xyz 1346 : 2046 : timestamp2date_safe(Timestamp timestamp, Node *escontext)
1347 : : {
1348 : : DateADT result;
1349 : : struct pg_tm tt,
8321 tgl@sss.pgh.pa.us 1350 :CBC 2046 : *tm = &tt;
1351 : : fsec_t fsec;
1352 : :
6412 1353 [ + + ]: 2046 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
6412 tgl@sss.pgh.pa.us 1354 :GBC 6 : DATE_NOBEGIN(result);
6412 tgl@sss.pgh.pa.us 1355 [ + + ]:CBC 2040 : else if (TIMESTAMP_IS_NOEND(timestamp))
6412 tgl@sss.pgh.pa.us 1356 :GBC 6 : DATE_NOEND(result);
1357 : : else
1358 : : {
6412 tgl@sss.pgh.pa.us 1359 [ - + ]:CBC 2034 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
1360 : : {
155 michael@paquier.xyz 1361 [ # # ]:UNC 0 : if (timestamp < 0)
1362 : 0 : DATE_NOBEGIN(result);
1363 : : else
1364 : 0 : DATE_NOEND(result); /* not actually reachable */
1365 : :
1366 [ # # ]: 0 : ereturn(escontext, result,
1367 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1368 : : errmsg("timestamp out of range")));
1369 : : }
1370 : :
6412 tgl@sss.pgh.pa.us 1371 :CBC 2034 : result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1372 : : }
1373 : :
306 tgl@sss.pgh.pa.us 1374 :GNC 2046 : return result;
1375 : : }
1376 : :
1377 : :
1378 : : /* date_timestamptz()
1379 : : * Convert date to timestamp with time zone data type.
1380 : : */
1381 : : Datum
8985 lockhart@fourpalms.o 1382 :CBC 145 : date_timestamptz(PG_FUNCTION_ARGS)
1383 : : {
1384 : 145 : DateADT dateVal = PG_GETARG_DATEADT(0);
1385 : : TimestampTz result;
1386 : :
42 peter@eisentraut.org 1387 :GNC 145 : result = date2timestamptz_safe(dateVal, fcinfo->context);
1388 [ - + - - : 137 : if (SOFT_ERROR_OCCURRED(fcinfo->context))
- - ]
42 peter@eisentraut.org 1389 :UNC 0 : PG_RETURN_NULL();
1390 : :
9461 tgl@sss.pgh.pa.us 1391 :CBC 137 : PG_RETURN_TIMESTAMP(result);
1392 : : }
1393 : :
1394 : :
1395 : : /* timestamptz_date()
1396 : : * Convert timestamp with time zone to date data type.
1397 : : */
1398 : : Datum
8985 lockhart@fourpalms.o 1399 : 1998 : timestamptz_date(PG_FUNCTION_ARGS)
1400 : : {
8958 bruce@momjian.us 1401 : 1998 : TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
1402 : : DateADT result;
1403 : :
42 peter@eisentraut.org 1404 :GNC 1998 : result = timestamptz2date_safe(timestamp, fcinfo->context);
41 1405 [ - + - - : 1998 : if (SOFT_ERROR_OCCURRED(fcinfo->context))
- - ]
42 peter@eisentraut.org 1406 :UNC 0 : PG_RETURN_NULL();
1407 : :
306 tgl@sss.pgh.pa.us 1408 :GNC 1998 : PG_RETURN_DATEADT(result);
1409 : : }
1410 : :
1411 : : /*
1412 : : * Convert timestamptz to date.
1413 : : *
1414 : : * If the timestamp falls out of the valid range for the date type, error
1415 : : * handling proceeds based on escontext.
1416 : : *
1417 : : * If escontext is NULL, we throw an out-of-range error (hard error).
1418 : : * If escontext is not NULL, we return NOBEGIN or NOEND for lower bound or
1419 : : * upper bound overflow, respectively, and record a soft error.
1420 : : *
1421 : : * Note: given the ranges of the types, overflow is only possible at
1422 : : * the lower bound of the range, but we don't assume that in this code.
1423 : : */
1424 : : DateADT
155 michael@paquier.xyz 1425 : 2022 : timestamptz2date_safe(TimestampTz timestamp, Node *escontext)
1426 : : {
1427 : : DateADT result;
1428 : : struct pg_tm tt,
9575 lockhart@fourpalms.o 1429 :CBC 2022 : *tm = &tt;
1430 : : fsec_t fsec;
1431 : : int tz;
1432 : :
6412 tgl@sss.pgh.pa.us 1433 [ + + ]: 2022 : if (TIMESTAMP_IS_NOBEGIN(timestamp))
6412 tgl@sss.pgh.pa.us 1434 :GBC 6 : DATE_NOBEGIN(result);
6412 tgl@sss.pgh.pa.us 1435 [ + + ]:CBC 2016 : else if (TIMESTAMP_IS_NOEND(timestamp))
6412 tgl@sss.pgh.pa.us 1436 :GBC 6 : DATE_NOEND(result);
1437 : : else
1438 : : {
5164 peter_e@gmx.net 1439 [ - + ]:CBC 2010 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
1440 : : {
155 michael@paquier.xyz 1441 [ # # ]:UNC 0 : if (timestamp < 0)
1442 : 0 : DATE_NOBEGIN(result);
1443 : : else
1444 : 0 : DATE_NOEND(result); /* not actually reachable */
1445 : :
1446 [ # # ]: 0 : ereturn(escontext, result,
1447 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1448 : : errmsg("timestamp out of range")));
1449 : : }
1450 : :
6412 tgl@sss.pgh.pa.us 1451 :CBC 2010 : result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
1452 : : }
1453 : :
306 tgl@sss.pgh.pa.us 1454 :GNC 2022 : return result;
1455 : : }
1456 : :
1457 : :
1458 : : /*****************************************************************************
1459 : : * Time ADT
1460 : : *****************************************************************************/
1461 : :
1462 : : Datum
9461 tgl@sss.pgh.pa.us 1463 :CBC 1424 : time_in(PG_FUNCTION_ARGS)
1464 : : {
1465 : 1424 : char *str = PG_GETARG_CSTRING(0);
1466 : : #ifdef NOT_USED
1467 : : Oid typelem = PG_GETARG_OID(1);
1468 : : #endif
8980 lockhart@fourpalms.o 1469 : 1424 : int32 typmod = PG_GETARG_INT32(2);
1243 tgl@sss.pgh.pa.us 1470 : 1424 : Node *escontext = fcinfo->context;
1471 : : TimeADT result;
1472 : : fsec_t fsec;
1473 : : struct pg_tm tt,
9575 lockhart@fourpalms.o 1474 : 1424 : *tm = &tt;
1475 : : int tz;
1476 : : int nf;
1477 : : int dterr;
1478 : : char workbuf[MAXDATELEN + 1];
1479 : : char *field[MAXDATEFIELDS];
1480 : : int dtype;
1481 : : int ftype[MAXDATEFIELDS];
1482 : : DateTimeErrorExtra extra;
1483 : :
7649 neilc@samurai.com 1484 : 1424 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
1485 : : field, ftype, MAXDATEFIELDS, &nf);
8287 tgl@sss.pgh.pa.us 1486 [ + - ]: 1424 : if (dterr == 0)
1243 1487 : 1424 : dterr = DecodeTimeOnly(field, ftype, nf,
1488 : : &dtype, tm, &fsec, &tz, &extra);
8287 1489 [ + + ]: 1424 : if (dterr != 0)
1490 : : {
1243 1491 : 40 : DateTimeParseError(dterr, &extra, str, "time", escontext);
1492 : 16 : PG_RETURN_NULL();
1493 : : }
1494 : :
8780 lockhart@fourpalms.o 1495 : 1384 : tm2time(tm, fsec, &result);
8980 1496 : 1384 : AdjustTimeForTypmod(&result, typmod);
1497 : :
1498 : 1384 : PG_RETURN_TIMEADT(result);
1499 : : }
1500 : :
1501 : : /* tm2time()
1502 : : * Convert a tm structure to a time data type.
1503 : : */
1504 : : int
3240 tgl@sss.pgh.pa.us 1505 : 2309 : tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
1506 : : {
7593 bruce@momjian.us 1507 : 2309 : *result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec)
7507 1508 : 2309 : * USECS_PER_SEC) + fsec;
8780 lockhart@fourpalms.o 1509 : 2309 : return 0;
1510 : : }
1511 : :
1512 : : /* time_overflows()
1513 : : * Check to see if a broken-down time-of-day is out of range.
1514 : : */
1515 : : bool
2161 tgl@sss.pgh.pa.us 1516 : 31098 : time_overflows(int hour, int min, int sec, fsec_t fsec)
1517 : : {
1518 : : /* Range-check the fields individually. */
1519 [ + - + + : 31098 : if (hour < 0 || hour > HOURS_PER_DAY ||
+ - ]
1520 [ + - + - ]: 31074 : min < 0 || min >= MINS_PER_HOUR ||
1521 [ + - + - ]: 31074 : sec < 0 || sec > SECS_PER_MINUTE ||
1522 [ - + ]: 31074 : fsec < 0 || fsec > USECS_PER_SEC)
1523 : 24 : return true;
1524 : :
1525 : : /*
1526 : : * Because we allow, eg, hour = 24 or sec = 60, we must check separately
1527 : : * that the total time value doesn't exceed 24:00:00.
1528 : : */
1529 : 31074 : if ((((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
1530 [ + + ]: 31074 : + sec) * USECS_PER_SEC) + fsec) > USECS_PER_DAY)
1531 : 24 : return true;
1532 : :
1533 : 31050 : return false;
1534 : : }
1535 : :
1536 : : /* float_time_overflows()
1537 : : * Same, when we have seconds + fractional seconds as one "double" value.
1538 : : */
1539 : : bool
1540 : 168 : float_time_overflows(int hour, int min, double sec)
1541 : : {
1542 : : /* Range-check the fields individually. */
1543 [ + - + - : 168 : if (hour < 0 || hour > HOURS_PER_DAY ||
+ - ]
1544 [ - + ]: 168 : min < 0 || min >= MINS_PER_HOUR)
2161 tgl@sss.pgh.pa.us 1545 :UBC 0 : return true;
1546 : :
1547 : : /*
1548 : : * "sec", being double, requires extra care. Cope with NaN, and round off
1549 : : * before applying the range check to avoid unexpected errors due to
1550 : : * imprecise input. (We assume rint() behaves sanely with infinities.)
1551 : : */
2161 tgl@sss.pgh.pa.us 1552 [ - + ]:CBC 168 : if (isnan(sec))
2161 tgl@sss.pgh.pa.us 1553 :UBC 0 : return true;
2161 tgl@sss.pgh.pa.us 1554 :CBC 168 : sec = rint(sec * USECS_PER_SEC);
1555 [ + - + + ]: 168 : if (sec < 0 || sec > SECS_PER_MINUTE * USECS_PER_SEC)
1556 : 4 : return true;
1557 : :
1558 : : /*
1559 : : * Because we allow, eg, hour = 24 or sec = 60, we must check separately
1560 : : * that the total time value doesn't exceed 24:00:00. This must match the
1561 : : * way that callers will convert the fields to a time.
1562 : : */
1563 : 164 : if (((((hour * MINS_PER_HOUR + min) * SECS_PER_MINUTE)
1564 [ + + ]: 164 : * USECS_PER_SEC) + (int64) sec) > USECS_PER_DAY)
1565 : 4 : return true;
1566 : :
1567 : 160 : return false;
1568 : : }
1569 : :
1570 : :
1571 : : /* time2tm()
1572 : : * Convert time data type to POSIX time structure.
1573 : : *
1574 : : * Note that only the hour/min/sec/fractional-sec fields are filled in.
1575 : : */
1576 : : int
3240 1577 : 4311 : time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
1578 : : {
7651 bruce@momjian.us 1579 : 4311 : tm->tm_hour = time / USECS_PER_HOUR;
1580 : 4311 : time -= tm->tm_hour * USECS_PER_HOUR;
1581 : 4311 : tm->tm_min = time / USECS_PER_MINUTE;
1582 : 4311 : time -= tm->tm_min * USECS_PER_MINUTE;
1583 : 4311 : tm->tm_sec = time / USECS_PER_SEC;
1584 : 4311 : time -= tm->tm_sec * USECS_PER_SEC;
8780 lockhart@fourpalms.o 1585 : 4311 : *fsec = time;
1586 : 4311 : return 0;
1587 : : }
1588 : :
1589 : : Datum
9461 tgl@sss.pgh.pa.us 1590 : 3875 : time_out(PG_FUNCTION_ARGS)
1591 : : {
1592 : 3875 : TimeADT time = PG_GETARG_TIMEADT(0);
1593 : : char *result;
1594 : : struct pg_tm tt,
9575 lockhart@fourpalms.o 1595 : 3875 : *tm = &tt;
1596 : : fsec_t fsec;
1597 : : char buf[MAXDATELEN + 1];
1598 : :
8780 1599 : 3875 : time2tm(time, tm, &fsec);
5165 peter_e@gmx.net 1600 : 3875 : EncodeTimeOnly(tm, fsec, false, 0, DateStyle, buf);
1601 : :
9461 tgl@sss.pgh.pa.us 1602 : 3875 : result = pstrdup(buf);
1603 : 3875 : PG_RETURN_CSTRING(result);
1604 : : }
1605 : :
1606 : : /*
1607 : : * time_recv - converts external binary format to time
1608 : : */
1609 : : Datum
8394 tgl@sss.pgh.pa.us 1610 :UBC 0 : time_recv(PG_FUNCTION_ARGS)
1611 : : {
1612 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1613 : :
1614 : : #ifdef NOT_USED
1615 : : Oid typelem = PG_GETARG_OID(1);
1616 : : #endif
7604 1617 : 0 : int32 typmod = PG_GETARG_INT32(2);
1618 : : TimeADT result;
1619 : :
1620 : 0 : result = pq_getmsgint64(buf);
1621 : :
6188 1622 [ # # # # ]: 0 : if (result < INT64CONST(0) || result > USECS_PER_DAY)
1623 [ # # ]: 0 : ereport(ERROR,
1624 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1625 : : errmsg("time out of range")));
1626 : :
7604 1627 : 0 : AdjustTimeForTypmod(&result, typmod);
1628 : :
1629 : 0 : PG_RETURN_TIMEADT(result);
1630 : : }
1631 : :
1632 : : /*
1633 : : * time_send - converts time to binary format
1634 : : */
1635 : : Datum
8394 1636 : 0 : time_send(PG_FUNCTION_ARGS)
1637 : : {
1638 : 0 : TimeADT time = PG_GETARG_TIMEADT(0);
1639 : : StringInfoData buf;
1640 : :
1641 : 0 : pq_begintypsend(&buf);
1642 : 0 : pq_sendint64(&buf, time);
1643 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1644 : : }
1645 : :
1646 : : Datum
7066 tgl@sss.pgh.pa.us 1647 :CBC 14 : timetypmodin(PG_FUNCTION_ARGS)
1648 : : {
6746 bruce@momjian.us 1649 : 14 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1650 : :
7066 tgl@sss.pgh.pa.us 1651 : 14 : PG_RETURN_INT32(anytime_typmodin(false, ta));
1652 : : }
1653 : :
1654 : : Datum
1655 : 5 : timetypmodout(PG_FUNCTION_ARGS)
1656 : : {
6746 bruce@momjian.us 1657 : 5 : int32 typmod = PG_GETARG_INT32(0);
1658 : :
7066 tgl@sss.pgh.pa.us 1659 : 5 : PG_RETURN_CSTRING(anytime_typmodout(false, typmod));
1660 : : }
1661 : :
1662 : : /*
1663 : : * make_time - time constructor
1664 : : */
1665 : : Datum
4552 1666 : 13 : make_time(PG_FUNCTION_ARGS)
1667 : : {
1668 : 13 : int tm_hour = PG_GETARG_INT32(0);
1669 : 13 : int tm_min = PG_GETARG_INT32(1);
1670 : 13 : double sec = PG_GETARG_FLOAT8(2);
1671 : : TimeADT time;
1672 : :
1673 : : /* Check for time overflow */
2161 1674 [ + + ]: 13 : if (float_time_overflows(tm_hour, tm_min, sec))
4552 1675 [ + - ]: 8 : ereport(ERROR,
1676 : : (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
1677 : : errmsg("time field value out of range: %d:%02d:%02g",
1678 : : tm_hour, tm_min, sec)));
1679 : :
1680 : : /* This should match tm2time */
1681 : 5 : time = (((tm_hour * MINS_PER_HOUR + tm_min) * SECS_PER_MINUTE)
2161 1682 : 5 : * USECS_PER_SEC) + (int64) rint(sec * USECS_PER_SEC);
1683 : :
4552 1684 : 5 : PG_RETURN_TIMEADT(time);
1685 : : }
1686 : :
1687 : :
1688 : : /* time_support()
1689 : : *
1690 : : * Planner support function for the time_scale() and timetz_scale()
1691 : : * length coercion functions (we need not distinguish them here).
1692 : : */
1693 : : Datum
2642 1694 : 20 : time_support(PG_FUNCTION_ARGS)
1695 : : {
1696 : 20 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1697 : 20 : Node *ret = NULL;
1698 : :
1699 [ + + ]: 20 : if (IsA(rawreq, SupportRequestSimplify))
1700 : : {
1701 : 10 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1702 : :
1703 : 10 : ret = TemporalSimplify(MAX_TIME_PRECISION, (Node *) req->fcall);
1704 : : }
1705 : :
1706 : 20 : PG_RETURN_POINTER(ret);
1707 : : }
1708 : :
1709 : : /* time_scale()
1710 : : * Adjust time type for specified scale factor.
1711 : : * Used by PostgreSQL type system to stuff columns.
1712 : : */
1713 : : Datum
8980 lockhart@fourpalms.o 1714 : 54 : time_scale(PG_FUNCTION_ARGS)
1715 : : {
1716 : 54 : TimeADT time = PG_GETARG_TIMEADT(0);
1717 : 54 : int32 typmod = PG_GETARG_INT32(1);
1718 : : TimeADT result;
1719 : :
1720 : 54 : result = time;
1721 : 54 : AdjustTimeForTypmod(&result, typmod);
1722 : :
1723 : 54 : PG_RETURN_TIMEADT(result);
1724 : : }
1725 : :
1726 : : /* AdjustTimeForTypmod()
1727 : : * Force the precision of the time value to a specified value.
1728 : : * Uses *exactly* the same code as in AdjustTimestampForTypmod()
1729 : : * but we make a separate copy because those types do not
1730 : : * have a fundamental tie together but rather a coincidence of
1731 : : * implementation. - thomas
1732 : : */
1733 : : void
1734 : 5176 : AdjustTimeForTypmod(TimeADT *time, int32 typmod)
1735 : : {
1736 : : static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
1737 : : INT64CONST(1000000),
1738 : : INT64CONST(100000),
1739 : : INT64CONST(10000),
1740 : : INT64CONST(1000),
1741 : : INT64CONST(100),
1742 : : INT64CONST(10),
1743 : : INT64CONST(1)
1744 : : };
1745 : :
1746 : : static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
1747 : : INT64CONST(500000),
1748 : : INT64CONST(50000),
1749 : : INT64CONST(5000),
1750 : : INT64CONST(500),
1751 : : INT64CONST(50),
1752 : : INT64CONST(5),
1753 : : INT64CONST(0)
1754 : : };
1755 : :
7651 bruce@momjian.us 1756 [ + + + - ]: 5176 : if (typmod >= 0 && typmod <= MAX_TIME_PRECISION)
1757 : : {
8675 lockhart@fourpalms.o 1758 [ + - ]: 374 : if (*time >= INT64CONST(0))
7651 bruce@momjian.us 1759 : 374 : *time = ((*time + TimeOffsets[typmod]) / TimeScales[typmod]) *
7507 1760 : 374 : TimeScales[typmod];
1761 : : else
7651 bruce@momjian.us 1762 :UBC 0 : *time = -((((-*time) + TimeOffsets[typmod]) / TimeScales[typmod]) *
7507 1763 : 0 : TimeScales[typmod]);
1764 : : }
8980 lockhart@fourpalms.o 1765 :CBC 5176 : }
1766 : :
1767 : :
1768 : : Datum
9461 tgl@sss.pgh.pa.us 1769 : 25556 : time_eq(PG_FUNCTION_ARGS)
1770 : : {
1771 : 25556 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1772 : 25556 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1773 : :
1774 : 25556 : PG_RETURN_BOOL(time1 == time2);
1775 : : }
1776 : :
1777 : : Datum
9461 tgl@sss.pgh.pa.us 1778 :UBC 0 : time_ne(PG_FUNCTION_ARGS)
1779 : : {
1780 : 0 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1781 : 0 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1782 : :
1783 : 0 : PG_RETURN_BOOL(time1 != time2);
1784 : : }
1785 : :
1786 : : Datum
9461 tgl@sss.pgh.pa.us 1787 :CBC 62473 : time_lt(PG_FUNCTION_ARGS)
1788 : : {
1789 : 62473 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1790 : 62473 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1791 : :
1792 : 62473 : PG_RETURN_BOOL(time1 < time2);
1793 : : }
1794 : :
1795 : : Datum
1796 : 5515 : time_le(PG_FUNCTION_ARGS)
1797 : : {
1798 : 5515 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1799 : 5515 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1800 : :
1801 : 5515 : PG_RETURN_BOOL(time1 <= time2);
1802 : : }
1803 : :
1804 : : Datum
1805 : 6767 : time_gt(PG_FUNCTION_ARGS)
1806 : : {
1807 : 6767 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1808 : 6767 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1809 : :
1810 : 6767 : PG_RETURN_BOOL(time1 > time2);
1811 : : }
1812 : :
1813 : : Datum
1814 : 4151 : time_ge(PG_FUNCTION_ARGS)
1815 : : {
1816 : 4151 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1817 : 4151 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1818 : :
1819 : 4151 : PG_RETURN_BOOL(time1 >= time2);
1820 : : }
1821 : :
1822 : : Datum
1823 : 21364 : time_cmp(PG_FUNCTION_ARGS)
1824 : : {
1825 : 21364 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1826 : 21364 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1827 : :
1828 [ + + ]: 21364 : if (time1 < time2)
1829 : 10230 : PG_RETURN_INT32(-1);
1830 [ + + ]: 11134 : if (time1 > time2)
1831 : 9516 : PG_RETURN_INT32(1);
1832 : 1618 : PG_RETURN_INT32(0);
1833 : : }
1834 : :
1835 : : Datum
6878 1836 : 1516 : time_hash(PG_FUNCTION_ARGS)
1837 : : {
1838 : 1516 : return hashint8(fcinfo);
1839 : : }
1840 : :
1841 : : Datum
3169 rhaas@postgresql.org 1842 : 40 : time_hash_extended(PG_FUNCTION_ARGS)
1843 : : {
1844 : 40 : return hashint8extended(fcinfo);
1845 : : }
1846 : :
1847 : : Datum
9461 tgl@sss.pgh.pa.us 1848 :UBC 0 : time_larger(PG_FUNCTION_ARGS)
1849 : : {
1850 : 0 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1851 : 0 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1852 : :
1853 : 0 : PG_RETURN_TIMEADT((time1 > time2) ? time1 : time2);
1854 : : }
1855 : :
1856 : : Datum
1857 : 0 : time_smaller(PG_FUNCTION_ARGS)
1858 : : {
1859 : 0 : TimeADT time1 = PG_GETARG_TIMEADT(0);
1860 : 0 : TimeADT time2 = PG_GETARG_TIMEADT(1);
1861 : :
1862 : 0 : PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
1863 : : }
1864 : :
1865 : : /* overlaps_time() --- implements the SQL OVERLAPS operator.
1866 : : *
1867 : : * Algorithm is per SQL spec. This is much harder than you'd think
1868 : : * because the spec requires us to deliver a non-null answer in some cases
1869 : : * where some of the inputs are null.
1870 : : */
1871 : : Datum
9461 tgl@sss.pgh.pa.us 1872 :CBC 22 : overlaps_time(PG_FUNCTION_ARGS)
1873 : : {
1874 : : /*
1875 : : * The arguments are TimeADT, but we leave them as generic Datums to avoid
1876 : : * dereferencing nulls (TimeADT is pass-by-reference!)
1877 : : */
9280 1878 : 22 : Datum ts1 = PG_GETARG_DATUM(0);
1879 : 22 : Datum te1 = PG_GETARG_DATUM(1);
1880 : 22 : Datum ts2 = PG_GETARG_DATUM(2);
1881 : 22 : Datum te2 = PG_GETARG_DATUM(3);
1882 : 22 : bool ts1IsNull = PG_ARGISNULL(0);
1883 : 22 : bool te1IsNull = PG_ARGISNULL(1);
1884 : 22 : bool ts2IsNull = PG_ARGISNULL(2);
1885 : 22 : bool te2IsNull = PG_ARGISNULL(3);
1886 : :
1887 : : #define TIMEADT_GT(t1,t2) \
1888 : : (DatumGetTimeADT(t1) > DatumGetTimeADT(t2))
1889 : : #define TIMEADT_LT(t1,t2) \
1890 : : (DatumGetTimeADT(t1) < DatumGetTimeADT(t2))
1891 : :
1892 : : /*
1893 : : * If both endpoints of interval 1 are null, the result is null (unknown).
1894 : : * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
1895 : : * take ts1 as the lesser endpoint.
1896 : : */
1897 [ - + ]: 22 : if (ts1IsNull)
1898 : : {
9280 tgl@sss.pgh.pa.us 1899 [ # # ]:UBC 0 : if (te1IsNull)
1900 : 0 : PG_RETURN_NULL();
1901 : : /* swap null for non-null */
9548 lockhart@fourpalms.o 1902 : 0 : ts1 = te1;
9280 tgl@sss.pgh.pa.us 1903 : 0 : te1IsNull = true;
1904 : : }
9280 tgl@sss.pgh.pa.us 1905 [ + - ]:CBC 22 : else if (!te1IsNull)
1906 : : {
1907 [ - + ]: 22 : if (TIMEADT_GT(ts1, te1))
1908 : : {
9175 bruce@momjian.us 1909 :UBC 0 : Datum tt = ts1;
1910 : :
9280 tgl@sss.pgh.pa.us 1911 : 0 : ts1 = te1;
1912 : 0 : te1 = tt;
1913 : : }
1914 : : }
1915 : :
1916 : : /* Likewise for interval 2. */
9280 tgl@sss.pgh.pa.us 1917 [ - + ]:CBC 22 : if (ts2IsNull)
1918 : : {
9280 tgl@sss.pgh.pa.us 1919 [ # # ]:UBC 0 : if (te2IsNull)
1920 : 0 : PG_RETURN_NULL();
1921 : : /* swap null for non-null */
9548 lockhart@fourpalms.o 1922 : 0 : ts2 = te2;
9280 tgl@sss.pgh.pa.us 1923 : 0 : te2IsNull = true;
1924 : : }
9280 tgl@sss.pgh.pa.us 1925 [ + - ]:CBC 22 : else if (!te2IsNull)
1926 : : {
1927 [ - + ]: 22 : if (TIMEADT_GT(ts2, te2))
1928 : : {
9175 bruce@momjian.us 1929 :UBC 0 : Datum tt = ts2;
1930 : :
9280 tgl@sss.pgh.pa.us 1931 : 0 : ts2 = te2;
1932 : 0 : te2 = tt;
1933 : : }
1934 : : }
1935 : :
1936 : : /*
1937 : : * At this point neither ts1 nor ts2 is null, so we can consider three
1938 : : * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
1939 : : */
9280 tgl@sss.pgh.pa.us 1940 [ - + ]:CBC 22 : if (TIMEADT_GT(ts1, ts2))
1941 : : {
1942 : : /*
1943 : : * This case is ts1 < te2 OR te1 < te2, which may look redundant but
1944 : : * in the presence of nulls it's not quite completely so.
1945 : : */
9280 tgl@sss.pgh.pa.us 1946 [ # # ]:UBC 0 : if (te2IsNull)
1947 : 0 : PG_RETURN_NULL();
1948 [ # # ]: 0 : if (TIMEADT_LT(ts1, te2))
1949 : 0 : PG_RETURN_BOOL(true);
1950 [ # # ]: 0 : if (te1IsNull)
1951 : 0 : PG_RETURN_NULL();
1952 : :
1953 : : /*
1954 : : * If te1 is not null then we had ts1 <= te1 above, and we just found
1955 : : * ts1 >= te2, hence te1 >= te2.
1956 : : */
1957 : 0 : PG_RETURN_BOOL(false);
1958 : : }
9280 tgl@sss.pgh.pa.us 1959 [ + - ]:CBC 22 : else if (TIMEADT_LT(ts1, ts2))
1960 : : {
1961 : : /* This case is ts2 < te1 OR te2 < te1 */
1962 [ - + ]: 22 : if (te1IsNull)
9280 tgl@sss.pgh.pa.us 1963 :UBC 0 : PG_RETURN_NULL();
9280 tgl@sss.pgh.pa.us 1964 [ + + ]:CBC 22 : if (TIMEADT_LT(ts2, te1))
1965 : 11 : PG_RETURN_BOOL(true);
1966 [ - + ]: 11 : if (te2IsNull)
9280 tgl@sss.pgh.pa.us 1967 :UBC 0 : PG_RETURN_NULL();
1968 : :
1969 : : /*
1970 : : * If te2 is not null then we had ts2 <= te2 above, and we just found
1971 : : * ts2 >= te1, hence te2 >= te1.
1972 : : */
9280 tgl@sss.pgh.pa.us 1973 :CBC 11 : PG_RETURN_BOOL(false);
1974 : : }
1975 : : else
1976 : : {
1977 : : /*
1978 : : * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
1979 : : * rather silly way of saying "true if both are nonnull, else null".
1980 : : */
9280 tgl@sss.pgh.pa.us 1981 [ # # # # ]:UBC 0 : if (te1IsNull || te2IsNull)
1982 : 0 : PG_RETURN_NULL();
1983 : 0 : PG_RETURN_BOOL(true);
1984 : : }
1985 : :
1986 : : #undef TIMEADT_GT
1987 : : #undef TIMEADT_LT
1988 : : }
1989 : :
1990 : : /* timestamp_time()
1991 : : * Convert timestamp to time data type.
1992 : : */
1993 : : Datum
9461 tgl@sss.pgh.pa.us 1994 :CBC 24 : timestamp_time(PG_FUNCTION_ARGS)
1995 : : {
7507 bruce@momjian.us 1996 : 24 : Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
1997 : : TimeADT result;
1998 : : struct pg_tm tt,
10466 1999 : 24 : *tm = &tt;
2000 : : fsec_t fsec;
2001 : :
9461 tgl@sss.pgh.pa.us 2002 [ + - - + ]: 24 : if (TIMESTAMP_NOT_FINITE(timestamp))
8985 lockhart@fourpalms.o 2003 :UBC 0 : PG_RETURN_NULL();
2004 : :
7593 bruce@momjian.us 2005 [ - + ]:CBC 24 : if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0)
42 peter@eisentraut.org 2006 [ # # ]:UNC 0 : ereturn(fcinfo->context, (Datum) 0,
2007 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2008 : : errmsg("timestamp out of range")));
2009 : :
2010 : : /*
2011 : : * Could also do this with time = (timestamp / USECS_PER_DAY *
2012 : : * USECS_PER_DAY) - timestamp;
2013 : : */
7593 bruce@momjian.us 2014 :CBC 24 : result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
7507 2015 : 24 : USECS_PER_SEC) + fsec;
2016 : :
8780 lockhart@fourpalms.o 2017 : 24 : PG_RETURN_TIMEADT(result);
2018 : : }
2019 : :
2020 : : /* timestamptz_time()
2021 : : * Convert timestamptz to time data type.
2022 : : */
2023 : : Datum
2024 : 36 : timestamptz_time(PG_FUNCTION_ARGS)
2025 : : {
2026 : 36 : TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2027 : : TimeADT result;
2028 : : struct pg_tm tt,
2029 : 36 : *tm = &tt;
2030 : : int tz;
2031 : : fsec_t fsec;
2032 : :
2033 [ + - - + ]: 36 : if (TIMESTAMP_NOT_FINITE(timestamp))
8780 lockhart@fourpalms.o 2034 :UBC 0 : PG_RETURN_NULL();
2035 : :
5164 peter_e@gmx.net 2036 [ - + ]:CBC 36 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
42 peter@eisentraut.org 2037 [ # # ]:UNC 0 : ereturn(fcinfo->context, (Datum) 0,
2038 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2039 : : errmsg("timestamp out of range")));
2040 : :
2041 : : /*
2042 : : * Could also do this with time = (timestamp / USECS_PER_DAY *
2043 : : * USECS_PER_DAY) - timestamp;
2044 : : */
7593 bruce@momjian.us 2045 :CBC 36 : result = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
7507 2046 : 36 : USECS_PER_SEC) + fsec;
2047 : :
9461 tgl@sss.pgh.pa.us 2048 : 36 : PG_RETURN_TIMEADT(result);
2049 : : }
2050 : :
2051 : : /* datetime_timestamp()
2052 : : * Convert date and time to timestamp data type.
2053 : : */
2054 : : Datum
2055 : 25 : datetime_timestamp(PG_FUNCTION_ARGS)
2056 : : {
7507 bruce@momjian.us 2057 : 25 : DateADT date = PG_GETARG_DATEADT(0);
9461 tgl@sss.pgh.pa.us 2058 : 25 : TimeADT time = PG_GETARG_TIMEADT(1);
2059 : : Timestamp result;
2060 : :
6412 2061 : 25 : result = date2timestamp(date);
2062 [ + - + - ]: 25 : if (!TIMESTAMP_NOT_FINITE(result))
2063 : : {
2064 : 25 : result += time;
3702 2065 [ + - - + ]: 25 : if (!IS_VALID_TIMESTAMP(result))
3702 tgl@sss.pgh.pa.us 2066 [ # # ]:UBC 0 : ereport(ERROR,
2067 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2068 : : errmsg("timestamp out of range")));
2069 : : }
2070 : :
9461 tgl@sss.pgh.pa.us 2071 :CBC 25 : PG_RETURN_TIMESTAMP(result);
2072 : : }
2073 : :
2074 : : /* time_interval()
2075 : : * Convert time to interval data type.
2076 : : */
2077 : : Datum
2078 : 10 : time_interval(PG_FUNCTION_ARGS)
2079 : : {
2080 : 10 : TimeADT time = PG_GETARG_TIMEADT(0);
2081 : : Interval *result;
2082 : :
146 michael@paquier.xyz 2083 :GNC 10 : result = palloc_object(Interval);
2084 : :
9461 tgl@sss.pgh.pa.us 2085 :CBC 10 : result->time = time;
7594 bruce@momjian.us 2086 : 10 : result->day = 0;
9548 lockhart@fourpalms.o 2087 : 10 : result->month = 0;
2088 : :
9461 tgl@sss.pgh.pa.us 2089 : 10 : PG_RETURN_INTERVAL_P(result);
2090 : : }
2091 : :
2092 : : /* interval_time()
2093 : : * Convert interval to time data type.
2094 : : *
2095 : : * This is defined as producing the fractional-day portion of the interval.
2096 : : * Therefore, we can just ignore the months field. It is not real clear
2097 : : * what to do with negative intervals, but we choose to subtract the floor,
2098 : : * so that, say, '-2 hours' becomes '22:00:00'.
2099 : : */
2100 : : Datum
9284 lockhart@fourpalms.o 2101 : 23 : interval_time(PG_FUNCTION_ARGS)
2102 : : {
2103 : 23 : Interval *span = PG_GETARG_INTERVAL_P(0);
2104 : : TimeADT result;
2105 : :
903 dean.a.rasheed@gmail 2106 [ + + + - : 23 : if (INTERVAL_NOT_FINITE(span))
- + + + +
- + - ]
42 peter@eisentraut.org 2107 [ + - ]:GNC 8 : ereturn(fcinfo->context, (Datum) 0,
2108 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2109 : : errmsg("cannot convert infinite interval to time")));
2110 : :
908 dean.a.rasheed@gmail 2111 :CBC 15 : result = span->time % USECS_PER_DAY;
2112 [ + + ]: 15 : if (result < 0)
2113 : 5 : result += USECS_PER_DAY;
2114 : :
9284 lockhart@fourpalms.o 2115 : 15 : PG_RETURN_TIMEADT(result);
2116 : : }
2117 : :
2118 : : /* time_mi_time()
2119 : : * Subtract two times to produce an interval.
2120 : : */
2121 : : Datum
8985 2122 : 820 : time_mi_time(PG_FUNCTION_ARGS)
2123 : : {
2124 : 820 : TimeADT time1 = PG_GETARG_TIMEADT(0);
2125 : 820 : TimeADT time2 = PG_GETARG_TIMEADT(1);
2126 : : Interval *result;
2127 : :
146 michael@paquier.xyz 2128 :GNC 820 : result = palloc_object(Interval);
2129 : :
8985 lockhart@fourpalms.o 2130 :CBC 820 : result->month = 0;
7594 bruce@momjian.us 2131 : 820 : result->day = 0;
2132 : 820 : result->time = time1 - time2;
2133 : :
8985 lockhart@fourpalms.o 2134 : 820 : PG_RETURN_INTERVAL_P(result);
2135 : : }
2136 : :
2137 : : /* time_pl_interval()
2138 : : * Add interval to time.
2139 : : */
2140 : : Datum
9284 2141 : 1777 : time_pl_interval(PG_FUNCTION_ARGS)
2142 : : {
2143 : 1777 : TimeADT time = PG_GETARG_TIMEADT(0);
2144 : 1777 : Interval *span = PG_GETARG_INTERVAL_P(1);
2145 : : TimeADT result;
2146 : :
903 dean.a.rasheed@gmail 2147 [ + + + - : 1777 : if (INTERVAL_NOT_FINITE(span))
- + + + +
- + - ]
2148 [ + - ]: 8 : ereport(ERROR,
2149 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2150 : : errmsg("cannot add infinite interval to time")));
2151 : :
7593 bruce@momjian.us 2152 : 1769 : result = time + span->time;
2153 : 1769 : result -= result / USECS_PER_DAY * USECS_PER_DAY;
8780 lockhart@fourpalms.o 2154 [ + + ]: 1769 : if (result < INT64CONST(0))
7652 bruce@momjian.us 2155 : 4 : result += USECS_PER_DAY;
2156 : :
9284 lockhart@fourpalms.o 2157 : 1769 : PG_RETURN_TIMEADT(result);
2158 : : }
2159 : :
2160 : : /* time_mi_interval()
2161 : : * Subtract interval from time.
2162 : : */
2163 : : Datum
2164 : 413 : time_mi_interval(PG_FUNCTION_ARGS)
2165 : : {
2166 : 413 : TimeADT time = PG_GETARG_TIMEADT(0);
2167 : 413 : Interval *span = PG_GETARG_INTERVAL_P(1);
2168 : : TimeADT result;
2169 : :
903 dean.a.rasheed@gmail 2170 [ + + + - : 413 : if (INTERVAL_NOT_FINITE(span))
- + + + +
- + - ]
2171 [ + - ]: 8 : ereport(ERROR,
2172 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2173 : : errmsg("cannot subtract infinite interval from time")));
2174 : :
7593 bruce@momjian.us 2175 : 405 : result = time - span->time;
2176 : 405 : result -= result / USECS_PER_DAY * USECS_PER_DAY;
8780 lockhart@fourpalms.o 2177 [ + + ]: 405 : if (result < INT64CONST(0))
7652 bruce@momjian.us 2178 : 49 : result += USECS_PER_DAY;
2179 : :
9284 lockhart@fourpalms.o 2180 : 405 : PG_RETURN_TIMEADT(result);
2181 : : }
2182 : :
2183 : : /*
2184 : : * in_range support function for time.
2185 : : */
2186 : : Datum
3009 tgl@sss.pgh.pa.us 2187 : 640 : in_range_time_interval(PG_FUNCTION_ARGS)
2188 : : {
2189 : 640 : TimeADT val = PG_GETARG_TIMEADT(0);
2190 : 640 : TimeADT base = PG_GETARG_TIMEADT(1);
2191 : 640 : Interval *offset = PG_GETARG_INTERVAL_P(2);
2192 : 640 : bool sub = PG_GETARG_BOOL(3);
2193 : 640 : bool less = PG_GETARG_BOOL(4);
2194 : : TimeADT sum;
2195 : :
2196 : : /*
2197 : : * Like time_pl_interval/time_mi_interval, we disregard the month and day
2198 : : * fields of the offset. So our test for negative should too. This also
2199 : : * catches -infinity, so we only need worry about +infinity below.
2200 : : */
2201 [ + + ]: 640 : if (offset->time < 0)
2202 [ + - ]: 8 : ereport(ERROR,
2203 : : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2204 : : errmsg("invalid preceding or following size in window function")));
2205 : :
2206 : : /*
2207 : : * We can't use time_pl_interval/time_mi_interval here, because their
2208 : : * wraparound behavior would give wrong (or at least undesirable) answers.
2209 : : * Fortunately the equivalent non-wrapping behavior is trivial, except
2210 : : * that adding an infinite (or very large) interval might cause integer
2211 : : * overflow. Subtraction cannot overflow here.
2212 : : */
2213 [ + + ]: 632 : if (sub)
2214 : 316 : sum = base - offset->time;
903 dean.a.rasheed@gmail 2215 [ + + ]: 316 : else if (pg_add_s64_overflow(base, offset->time, &sum))
2216 : 144 : PG_RETURN_BOOL(less);
2217 : :
3009 tgl@sss.pgh.pa.us 2218 [ + + ]: 488 : if (less)
2219 : 220 : PG_RETURN_BOOL(val <= sum);
2220 : : else
2221 : 268 : PG_RETURN_BOOL(val >= sum);
2222 : : }
2223 : :
2224 : :
2225 : : /* time_part() and extract_time()
2226 : : * Extract specified field from time type.
2227 : : */
2228 : : static Datum
1855 peter@eisentraut.org 2229 : 62 : time_part_common(PG_FUNCTION_ARGS, bool retnumeric)
2230 : : {
6615 tgl@sss.pgh.pa.us 2231 : 62 : text *units = PG_GETARG_TEXT_PP(0);
8780 lockhart@fourpalms.o 2232 : 62 : TimeADT time = PG_GETARG_TIMEADT(1);
2233 : : int64 intresult;
2234 : : int type,
2235 : : val;
2236 : : char *lowunits;
2237 : :
6615 tgl@sss.pgh.pa.us 2238 [ - + ]: 62 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
2239 [ - + - - : 62 : VARSIZE_ANY_EXHDR(units),
- - - - -
+ ]
2240 : : false);
2241 : :
8780 lockhart@fourpalms.o 2242 : 62 : type = DecodeUnits(0, lowunits, &val);
2243 [ + + ]: 62 : if (type == UNKNOWN_FIELD)
2244 : 14 : type = DecodeSpecial(0, lowunits, &val);
2245 : :
2246 [ + + ]: 62 : if (type == UNITS)
2247 : : {
2248 : : fsec_t fsec;
2249 : : struct pg_tm tt,
2250 : 48 : *tm = &tt;
2251 : :
2252 : 48 : time2tm(time, tm, &fsec);
2253 : :
2254 [ + + + + : 48 : switch (val)
+ + ]
2255 : : {
2256 : 10 : case DTK_MICROSEC:
1850 tgl@sss.pgh.pa.us 2257 : 10 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
8780 lockhart@fourpalms.o 2258 : 10 : break;
2259 : :
2260 : 10 : case DTK_MILLISEC:
1855 peter@eisentraut.org 2261 [ + + ]: 10 : if (retnumeric)
2262 : : /*---
2263 : : * tm->tm_sec * 1000 + fsec / 1000
2264 : : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
2265 : : */
1850 tgl@sss.pgh.pa.us 2266 : 20 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
2267 : : else
1855 peter@eisentraut.org 2268 : 5 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
2269 : : break;
2270 : :
8780 lockhart@fourpalms.o 2271 : 10 : case DTK_SECOND:
1855 peter@eisentraut.org 2272 [ + + ]: 10 : if (retnumeric)
2273 : : /*---
2274 : : * tm->tm_sec + fsec / 1'000'000
2275 : : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
2276 : : */
1850 tgl@sss.pgh.pa.us 2277 : 5 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
2278 : : else
1855 peter@eisentraut.org 2279 : 5 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
2280 : : break;
2281 : :
8780 lockhart@fourpalms.o 2282 : 5 : case DTK_MINUTE:
1855 peter@eisentraut.org 2283 : 5 : intresult = tm->tm_min;
8780 lockhart@fourpalms.o 2284 : 5 : break;
2285 : :
2286 : 5 : case DTK_HOUR:
1855 peter@eisentraut.org 2287 : 5 : intresult = tm->tm_hour;
8780 lockhart@fourpalms.o 2288 : 5 : break;
2289 : :
2290 : 8 : case DTK_TZ:
2291 : : case DTK_TZ_MINUTE:
2292 : : case DTK_TZ_HOUR:
2293 : : case DTK_DAY:
2294 : : case DTK_MONTH:
2295 : : case DTK_QUARTER:
2296 : : case DTK_YEAR:
2297 : : case DTK_DECADE:
2298 : : case DTK_CENTURY:
2299 : : case DTK_MILLENNIUM:
2300 : : case DTK_ISOYEAR:
2301 : : default:
8318 tgl@sss.pgh.pa.us 2302 [ + - ]: 8 : ereport(ERROR,
2303 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2304 : : errmsg("unit \"%s\" not supported for type %s",
2305 : : lowunits, format_type_be(TIMEOID))));
2306 : : intresult = 0;
2307 : : }
2308 : : }
7651 bruce@momjian.us 2309 [ + + + - ]: 14 : else if (type == RESERV && val == DTK_EPOCH)
2310 : : {
1855 peter@eisentraut.org 2311 [ + + ]: 10 : if (retnumeric)
2312 : 5 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time, 6));
2313 : : else
2314 : 5 : PG_RETURN_FLOAT8(time / 1000000.0);
2315 : : }
2316 : : else
2317 : : {
8318 tgl@sss.pgh.pa.us 2318 [ + - ]: 4 : ereport(ERROR,
2319 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2320 : : errmsg("unit \"%s\" not recognized for type %s",
2321 : : lowunits, format_type_be(TIMEOID))));
2322 : : intresult = 0;
2323 : : }
2324 : :
1855 peter@eisentraut.org 2325 [ + + ]: 20 : if (retnumeric)
2326 : 15 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
2327 : : else
2328 : 5 : PG_RETURN_FLOAT8(intresult);
2329 : : }
2330 : :
2331 : : Datum
2332 : 20 : time_part(PG_FUNCTION_ARGS)
2333 : : {
2334 : 20 : return time_part_common(fcinfo, false);
2335 : : }
2336 : :
2337 : : Datum
2338 : 42 : extract_time(PG_FUNCTION_ARGS)
2339 : : {
2340 : 42 : return time_part_common(fcinfo, true);
2341 : : }
2342 : :
2343 : :
2344 : : /*****************************************************************************
2345 : : * Time With Time Zone ADT
2346 : : *****************************************************************************/
2347 : :
2348 : : /* tm2timetz()
2349 : : * Convert a tm structure to a time data type.
2350 : : */
2351 : : int
3240 tgl@sss.pgh.pa.us 2352 : 2549 : tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
2353 : : {
7593 bruce@momjian.us 2354 : 2549 : result->time = ((((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec) *
7651 2355 : 2549 : USECS_PER_SEC) + fsec;
8780 lockhart@fourpalms.o 2356 : 2549 : result->zone = tz;
2357 : :
2358 : 2549 : return 0;
2359 : : }
2360 : :
2361 : : Datum
9461 tgl@sss.pgh.pa.us 2362 : 1364 : timetz_in(PG_FUNCTION_ARGS)
2363 : : {
2364 : 1364 : char *str = PG_GETARG_CSTRING(0);
2365 : : #ifdef NOT_USED
2366 : : Oid typelem = PG_GETARG_OID(1);
2367 : : #endif
8980 lockhart@fourpalms.o 2368 : 1364 : int32 typmod = PG_GETARG_INT32(2);
1243 tgl@sss.pgh.pa.us 2369 : 1364 : Node *escontext = fcinfo->context;
2370 : : TimeTzADT *result;
2371 : : fsec_t fsec;
2372 : : struct pg_tm tt,
9548 lockhart@fourpalms.o 2373 : 1364 : *tm = &tt;
2374 : : int tz;
2375 : : int nf;
2376 : : int dterr;
2377 : : char workbuf[MAXDATELEN + 1];
2378 : : char *field[MAXDATEFIELDS];
2379 : : int dtype;
2380 : : int ftype[MAXDATEFIELDS];
2381 : : DateTimeErrorExtra extra;
2382 : :
7649 neilc@samurai.com 2383 : 1364 : dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
2384 : : field, ftype, MAXDATEFIELDS, &nf);
8287 tgl@sss.pgh.pa.us 2385 [ + - ]: 1364 : if (dterr == 0)
1243 2386 : 1364 : dterr = DecodeTimeOnly(field, ftype, nf,
2387 : : &dtype, tm, &fsec, &tz, &extra);
8287 2388 [ + + ]: 1364 : if (dterr != 0)
2389 : : {
1243 2390 : 52 : DateTimeParseError(dterr, &extra, str, "time with time zone",
2391 : : escontext);
2392 : 16 : PG_RETURN_NULL();
2393 : : }
2394 : :
146 michael@paquier.xyz 2395 :GNC 1312 : result = palloc_object(TimeTzADT);
8780 lockhart@fourpalms.o 2396 :CBC 1312 : tm2timetz(tm, fsec, tz, result);
8980 2397 : 1312 : AdjustTimeForTypmod(&(result->time), typmod);
2398 : :
2399 : 1312 : PG_RETURN_TIMETZADT_P(result);
2400 : : }
2401 : :
2402 : : Datum
9461 tgl@sss.pgh.pa.us 2403 : 4207 : timetz_out(PG_FUNCTION_ARGS)
2404 : : {
2405 : 4207 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2406 : : char *result;
2407 : : struct pg_tm tt,
9548 lockhart@fourpalms.o 2408 : 4207 : *tm = &tt;
2409 : : fsec_t fsec;
2410 : : int tz;
2411 : : char buf[MAXDATELEN + 1];
2412 : :
8780 2413 : 4207 : timetz2tm(time, tm, &fsec, &tz);
5165 peter_e@gmx.net 2414 : 4207 : EncodeTimeOnly(tm, fsec, true, tz, DateStyle, buf);
2415 : :
8780 lockhart@fourpalms.o 2416 : 4207 : result = pstrdup(buf);
2417 : 4207 : PG_RETURN_CSTRING(result);
2418 : : }
2419 : :
2420 : : /*
2421 : : * timetz_recv - converts external binary format to timetz
2422 : : */
2423 : : Datum
8394 tgl@sss.pgh.pa.us 2424 :UBC 0 : timetz_recv(PG_FUNCTION_ARGS)
2425 : : {
2426 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
2427 : :
2428 : : #ifdef NOT_USED
2429 : : Oid typelem = PG_GETARG_OID(1);
2430 : : #endif
7604 2431 : 0 : int32 typmod = PG_GETARG_INT32(2);
2432 : : TimeTzADT *result;
2433 : :
146 michael@paquier.xyz 2434 :UNC 0 : result = palloc_object(TimeTzADT);
2435 : :
7604 tgl@sss.pgh.pa.us 2436 :UBC 0 : result->time = pq_getmsgint64(buf);
2437 : :
6188 2438 [ # # # # ]: 0 : if (result->time < INT64CONST(0) || result->time > USECS_PER_DAY)
2439 [ # # ]: 0 : ereport(ERROR,
2440 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2441 : : errmsg("time out of range")));
2442 : :
7604 2443 : 0 : result->zone = pq_getmsgint(buf, sizeof(result->zone));
2444 : :
2445 : : /* Check for sane GMT displacement; see notes in datatype/timestamp.h */
5088 2446 [ # # # # ]: 0 : if (result->zone <= -TZDISP_LIMIT || result->zone >= TZDISP_LIMIT)
6188 2447 [ # # ]: 0 : ereport(ERROR,
2448 : : (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
2449 : : errmsg("time zone displacement out of range")));
2450 : :
7604 2451 : 0 : AdjustTimeForTypmod(&(result->time), typmod);
2452 : :
2453 : 0 : PG_RETURN_TIMETZADT_P(result);
2454 : : }
2455 : :
2456 : : /*
2457 : : * timetz_send - converts timetz to binary format
2458 : : */
2459 : : Datum
8394 2460 : 0 : timetz_send(PG_FUNCTION_ARGS)
2461 : : {
2462 : 0 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2463 : : StringInfoData buf;
2464 : :
2465 : 0 : pq_begintypsend(&buf);
2466 : 0 : pq_sendint64(&buf, time->time);
3128 andres@anarazel.de 2467 : 0 : pq_sendint32(&buf, time->zone);
8394 tgl@sss.pgh.pa.us 2468 : 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2469 : : }
2470 : :
2471 : : Datum
7066 tgl@sss.pgh.pa.us 2472 :CBC 14 : timetztypmodin(PG_FUNCTION_ARGS)
2473 : : {
6746 bruce@momjian.us 2474 : 14 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
2475 : :
7066 tgl@sss.pgh.pa.us 2476 : 14 : PG_RETURN_INT32(anytime_typmodin(true, ta));
2477 : : }
2478 : :
2479 : : Datum
2480 : 5 : timetztypmodout(PG_FUNCTION_ARGS)
2481 : : {
6746 bruce@momjian.us 2482 : 5 : int32 typmod = PG_GETARG_INT32(0);
2483 : :
7066 tgl@sss.pgh.pa.us 2484 : 5 : PG_RETURN_CSTRING(anytime_typmodout(true, typmod));
2485 : : }
2486 : :
2487 : :
2488 : : /* timetz2tm()
2489 : : * Convert TIME WITH TIME ZONE data type to POSIX time structure.
2490 : : */
2491 : : int
3240 2492 : 4494 : timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp)
2493 : : {
6619 2494 : 4494 : TimeOffset trem = time->time;
2495 : :
7651 bruce@momjian.us 2496 : 4494 : tm->tm_hour = trem / USECS_PER_HOUR;
2497 : 4494 : trem -= tm->tm_hour * USECS_PER_HOUR;
2498 : 4494 : tm->tm_min = trem / USECS_PER_MINUTE;
2499 : 4494 : trem -= tm->tm_min * USECS_PER_MINUTE;
2500 : 4494 : tm->tm_sec = trem / USECS_PER_SEC;
2501 : 4494 : *fsec = trem - tm->tm_sec * USECS_PER_SEC;
2502 : :
8780 lockhart@fourpalms.o 2503 [ + - ]: 4494 : if (tzp != NULL)
2504 : 4494 : *tzp = time->zone;
2505 : :
2506 : 4494 : return 0;
2507 : : }
2508 : :
2509 : : /* timetz_scale()
2510 : : * Adjust time type for specified scale factor.
2511 : : * Used by PostgreSQL type system to stuff columns.
2512 : : */
2513 : : Datum
8980 2514 : 64 : timetz_scale(PG_FUNCTION_ARGS)
2515 : : {
2516 : 64 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2517 : 64 : int32 typmod = PG_GETARG_INT32(1);
2518 : : TimeTzADT *result;
2519 : :
146 michael@paquier.xyz 2520 :GNC 64 : result = palloc_object(TimeTzADT);
2521 : :
8980 lockhart@fourpalms.o 2522 :CBC 64 : result->time = time->time;
2523 : 64 : result->zone = time->zone;
2524 : :
2525 : 64 : AdjustTimeForTypmod(&(result->time), typmod);
2526 : :
2527 : 64 : PG_RETURN_TIMETZADT_P(result);
2528 : : }
2529 : :
2530 : :
2531 : : static int
9133 tgl@sss.pgh.pa.us 2532 : 138364 : timetz_cmp_internal(TimeTzADT *time1, TimeTzADT *time2)
2533 : : {
2534 : : TimeOffset t1,
2535 : : t2;
2536 : :
2537 : : /* Primary sort is by true (GMT-equivalent) time */
7652 bruce@momjian.us 2538 : 138364 : t1 = time1->time + (time1->zone * USECS_PER_SEC);
2539 : 138364 : t2 = time2->time + (time2->zone * USECS_PER_SEC);
2540 : :
9133 tgl@sss.pgh.pa.us 2541 [ + + ]: 138364 : if (t1 > t2)
2542 : 66170 : return 1;
2543 [ + + ]: 72194 : if (t1 < t2)
2544 : 65290 : return -1;
2545 : :
2546 : : /*
2547 : : * If same GMT time, sort by timezone; we only want to say that two
2548 : : * timetz's are equal if both the time and zone parts are equal.
2549 : : */
8985 lockhart@fourpalms.o 2550 [ + + ]: 6904 : if (time1->zone > time2->zone)
2551 : 52 : return 1;
2552 [ + + ]: 6852 : if (time1->zone < time2->zone)
2553 : 24 : return -1;
2554 : :
2555 : 6828 : return 0;
2556 : : }
2557 : :
2558 : : Datum
9461 tgl@sss.pgh.pa.us 2559 : 19247 : timetz_eq(PG_FUNCTION_ARGS)
2560 : : {
9175 bruce@momjian.us 2561 : 19247 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2562 : 19247 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2563 : :
9133 tgl@sss.pgh.pa.us 2564 : 19247 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) == 0);
2565 : : }
2566 : :
2567 : : Datum
9461 tgl@sss.pgh.pa.us 2568 :UBC 0 : timetz_ne(PG_FUNCTION_ARGS)
2569 : : {
9175 bruce@momjian.us 2570 : 0 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2571 : 0 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2572 : :
9133 tgl@sss.pgh.pa.us 2573 : 0 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) != 0);
2574 : : }
2575 : :
2576 : : Datum
9461 tgl@sss.pgh.pa.us 2577 :CBC 93134 : timetz_lt(PG_FUNCTION_ARGS)
2578 : : {
9175 bruce@momjian.us 2579 : 93134 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2580 : 93134 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2581 : :
9133 tgl@sss.pgh.pa.us 2582 : 93134 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) < 0);
2583 : : }
2584 : :
2585 : : Datum
9461 2586 : 4859 : timetz_le(PG_FUNCTION_ARGS)
2587 : : {
9175 bruce@momjian.us 2588 : 4859 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2589 : 4859 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2590 : :
9133 tgl@sss.pgh.pa.us 2591 : 4859 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) <= 0);
2592 : : }
2593 : :
2594 : : Datum
9461 2595 : 5472 : timetz_gt(PG_FUNCTION_ARGS)
2596 : : {
9175 bruce@momjian.us 2597 : 5472 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2598 : 5472 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2599 : :
9133 tgl@sss.pgh.pa.us 2600 : 5472 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) > 0);
2601 : : }
2602 : :
2603 : : Datum
9461 2604 : 4753 : timetz_ge(PG_FUNCTION_ARGS)
2605 : : {
9175 bruce@momjian.us 2606 : 4753 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2607 : 4753 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2608 : :
9133 tgl@sss.pgh.pa.us 2609 : 4753 : PG_RETURN_BOOL(timetz_cmp_internal(time1, time2) >= 0);
2610 : : }
2611 : :
2612 : : Datum
9461 2613 : 10407 : timetz_cmp(PG_FUNCTION_ARGS)
2614 : : {
9175 bruce@momjian.us 2615 : 10407 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2616 : 10407 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2617 : :
9133 tgl@sss.pgh.pa.us 2618 : 10407 : PG_RETURN_INT32(timetz_cmp_internal(time1, time2));
2619 : : }
2620 : :
2621 : : Datum
9451 2622 : 1516 : timetz_hash(PG_FUNCTION_ARGS)
2623 : : {
9175 bruce@momjian.us 2624 : 1516 : TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
2625 : : uint32 thash;
2626 : :
2627 : : /*
2628 : : * To avoid any problems with padding bytes in the struct, we figure the
2629 : : * field hashes separately and XOR them.
2630 : : */
6878 tgl@sss.pgh.pa.us 2631 : 1516 : thash = DatumGetUInt32(DirectFunctionCall1(hashint8,
2632 : : Int64GetDatumFast(key->time)));
2633 : 1516 : thash ^= DatumGetUInt32(hash_uint32(key->zone));
2634 : 1516 : PG_RETURN_UINT32(thash);
2635 : : }
2636 : :
2637 : : Datum
3169 rhaas@postgresql.org 2638 : 40 : timetz_hash_extended(PG_FUNCTION_ARGS)
2639 : : {
2640 : 40 : TimeTzADT *key = PG_GETARG_TIMETZADT_P(0);
3168 2641 : 40 : Datum seed = PG_GETARG_DATUM(1);
2642 : : uint64 thash;
2643 : :
2644 : : /* Same approach as timetz_hash */
3169 2645 : 40 : thash = DatumGetUInt64(DirectFunctionCall2(hashint8extended,
2646 : : Int64GetDatumFast(key->time),
2647 : : seed));
3168 2648 : 40 : thash ^= DatumGetUInt64(hash_uint32_extended(key->zone,
3079 2649 : 40 : DatumGetInt64(seed)));
3169 2650 : 40 : PG_RETURN_UINT64(thash);
2651 : : }
2652 : :
2653 : : Datum
9461 tgl@sss.pgh.pa.us 2654 :UBC 0 : timetz_larger(PG_FUNCTION_ARGS)
2655 : : {
9175 bruce@momjian.us 2656 : 0 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2657 : 0 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2658 : : TimeTzADT *result;
2659 : :
8306 tgl@sss.pgh.pa.us 2660 [ # # ]: 0 : if (timetz_cmp_internal(time1, time2) > 0)
2661 : 0 : result = time1;
2662 : : else
2663 : 0 : result = time2;
2664 : 0 : PG_RETURN_TIMETZADT_P(result);
2665 : : }
2666 : :
2667 : : Datum
9461 2668 : 0 : timetz_smaller(PG_FUNCTION_ARGS)
2669 : : {
9175 bruce@momjian.us 2670 : 0 : TimeTzADT *time1 = PG_GETARG_TIMETZADT_P(0);
2671 : 0 : TimeTzADT *time2 = PG_GETARG_TIMETZADT_P(1);
2672 : : TimeTzADT *result;
2673 : :
8306 tgl@sss.pgh.pa.us 2674 [ # # ]: 0 : if (timetz_cmp_internal(time1, time2) < 0)
2675 : 0 : result = time1;
2676 : : else
2677 : 0 : result = time2;
2678 : 0 : PG_RETURN_TIMETZADT_P(result);
2679 : : }
2680 : :
2681 : : /* timetz_pl_interval()
2682 : : * Add interval to timetz.
2683 : : */
2684 : : Datum
9284 lockhart@fourpalms.o 2685 :CBC 1813 : timetz_pl_interval(PG_FUNCTION_ARGS)
2686 : : {
2687 : 1813 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2688 : 1813 : Interval *span = PG_GETARG_INTERVAL_P(1);
2689 : : TimeTzADT *result;
2690 : :
903 dean.a.rasheed@gmail 2691 [ + + + - : 1813 : if (INTERVAL_NOT_FINITE(span))
- + + + +
- + - ]
2692 [ + - ]: 8 : ereport(ERROR,
2693 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2694 : : errmsg("cannot add infinite interval to time")));
2695 : :
146 michael@paquier.xyz 2696 :GNC 1805 : result = palloc_object(TimeTzADT);
2697 : :
7593 bruce@momjian.us 2698 :CBC 1805 : result->time = time->time + span->time;
2699 : 1805 : result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
8780 lockhart@fourpalms.o 2700 [ - + ]: 1805 : if (result->time < INT64CONST(0))
7652 bruce@momjian.us 2701 :UBC 0 : result->time += USECS_PER_DAY;
2702 : :
9284 lockhart@fourpalms.o 2703 :CBC 1805 : result->zone = time->zone;
2704 : :
2705 : 1805 : PG_RETURN_TIMETZADT_P(result);
2706 : : }
2707 : :
2708 : : /* timetz_mi_interval()
2709 : : * Subtract interval from timetz.
2710 : : */
2711 : : Datum
2712 : 493 : timetz_mi_interval(PG_FUNCTION_ARGS)
2713 : : {
2714 : 493 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(0);
2715 : 493 : Interval *span = PG_GETARG_INTERVAL_P(1);
2716 : : TimeTzADT *result;
2717 : :
903 dean.a.rasheed@gmail 2718 [ + + + - : 493 : if (INTERVAL_NOT_FINITE(span))
- + + + +
- + - ]
2719 [ + - ]: 8 : ereport(ERROR,
2720 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2721 : : errmsg("cannot subtract infinite interval from time")));
2722 : :
146 michael@paquier.xyz 2723 :GNC 485 : result = palloc_object(TimeTzADT);
2724 : :
7593 bruce@momjian.us 2725 :CBC 485 : result->time = time->time - span->time;
2726 : 485 : result->time -= result->time / USECS_PER_DAY * USECS_PER_DAY;
8780 lockhart@fourpalms.o 2727 [ + + ]: 485 : if (result->time < INT64CONST(0))
7652 bruce@momjian.us 2728 : 53 : result->time += USECS_PER_DAY;
2729 : :
9284 lockhart@fourpalms.o 2730 : 485 : result->zone = time->zone;
2731 : :
2732 : 485 : PG_RETURN_TIMETZADT_P(result);
2733 : : }
2734 : :
2735 : : /*
2736 : : * in_range support function for timetz.
2737 : : */
2738 : : Datum
3009 tgl@sss.pgh.pa.us 2739 : 692 : in_range_timetz_interval(PG_FUNCTION_ARGS)
2740 : : {
2741 : 692 : TimeTzADT *val = PG_GETARG_TIMETZADT_P(0);
2742 : 692 : TimeTzADT *base = PG_GETARG_TIMETZADT_P(1);
2743 : 692 : Interval *offset = PG_GETARG_INTERVAL_P(2);
2744 : 692 : bool sub = PG_GETARG_BOOL(3);
2745 : 692 : bool less = PG_GETARG_BOOL(4);
2746 : : TimeTzADT sum;
2747 : :
2748 : : /*
2749 : : * Like timetz_pl_interval/timetz_mi_interval, we disregard the month and
2750 : : * day fields of the offset. So our test for negative should too. This
2751 : : * also catches -infinity, so we only need worry about +infinity below.
2752 : : */
2753 [ + + ]: 692 : if (offset->time < 0)
2754 [ + - ]: 8 : ereport(ERROR,
2755 : : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2756 : : errmsg("invalid preceding or following size in window function")));
2757 : :
2758 : : /*
2759 : : * We can't use timetz_pl_interval/timetz_mi_interval here, because their
2760 : : * wraparound behavior would give wrong (or at least undesirable) answers.
2761 : : * Fortunately the equivalent non-wrapping behavior is trivial, except
2762 : : * that adding an infinite (or very large) interval might cause integer
2763 : : * overflow. Subtraction cannot overflow here.
2764 : : */
2765 [ + + ]: 684 : if (sub)
2766 : 316 : sum.time = base->time - offset->time;
903 dean.a.rasheed@gmail 2767 [ + + ]: 368 : else if (pg_add_s64_overflow(base->time, offset->time, &sum.time))
2768 : 192 : PG_RETURN_BOOL(less);
3009 tgl@sss.pgh.pa.us 2769 : 492 : sum.zone = base->zone;
2770 : :
2771 [ + + ]: 492 : if (less)
2772 : 224 : PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) <= 0);
2773 : : else
2774 : 268 : PG_RETURN_BOOL(timetz_cmp_internal(val, &sum) >= 0);
2775 : : }
2776 : :
2777 : : /* overlaps_timetz() --- implements the SQL OVERLAPS operator.
2778 : : *
2779 : : * Algorithm is per SQL spec. This is much harder than you'd think
2780 : : * because the spec requires us to deliver a non-null answer in some cases
2781 : : * where some of the inputs are null.
2782 : : */
2783 : : Datum
9461 tgl@sss.pgh.pa.us 2784 :UBC 0 : overlaps_timetz(PG_FUNCTION_ARGS)
2785 : : {
2786 : : /*
2787 : : * The arguments are TimeTzADT *, but we leave them as generic Datums for
2788 : : * convenience of notation --- and to avoid dereferencing nulls.
2789 : : */
2790 : 0 : Datum ts1 = PG_GETARG_DATUM(0);
2791 : 0 : Datum te1 = PG_GETARG_DATUM(1);
2792 : 0 : Datum ts2 = PG_GETARG_DATUM(2);
2793 : 0 : Datum te2 = PG_GETARG_DATUM(3);
9280 2794 : 0 : bool ts1IsNull = PG_ARGISNULL(0);
2795 : 0 : bool te1IsNull = PG_ARGISNULL(1);
2796 : 0 : bool ts2IsNull = PG_ARGISNULL(2);
2797 : 0 : bool te2IsNull = PG_ARGISNULL(3);
2798 : :
2799 : : #define TIMETZ_GT(t1,t2) \
2800 : : DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
2801 : : #define TIMETZ_LT(t1,t2) \
2802 : : DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
2803 : :
2804 : : /*
2805 : : * If both endpoints of interval 1 are null, the result is null (unknown).
2806 : : * If just one endpoint is null, take ts1 as the non-null one. Otherwise,
2807 : : * take ts1 as the lesser endpoint.
2808 : : */
2809 [ # # ]: 0 : if (ts1IsNull)
2810 : : {
2811 [ # # ]: 0 : if (te1IsNull)
2812 : 0 : PG_RETURN_NULL();
2813 : : /* swap null for non-null */
9548 lockhart@fourpalms.o 2814 : 0 : ts1 = te1;
9280 tgl@sss.pgh.pa.us 2815 : 0 : te1IsNull = true;
2816 : : }
2817 [ # # ]: 0 : else if (!te1IsNull)
2818 : : {
2819 [ # # ]: 0 : if (TIMETZ_GT(ts1, te1))
2820 : : {
9175 bruce@momjian.us 2821 : 0 : Datum tt = ts1;
2822 : :
9280 tgl@sss.pgh.pa.us 2823 : 0 : ts1 = te1;
2824 : 0 : te1 = tt;
2825 : : }
2826 : : }
2827 : :
2828 : : /* Likewise for interval 2. */
2829 [ # # ]: 0 : if (ts2IsNull)
2830 : : {
2831 [ # # ]: 0 : if (te2IsNull)
2832 : 0 : PG_RETURN_NULL();
2833 : : /* swap null for non-null */
9548 lockhart@fourpalms.o 2834 : 0 : ts2 = te2;
9280 tgl@sss.pgh.pa.us 2835 : 0 : te2IsNull = true;
2836 : : }
2837 [ # # ]: 0 : else if (!te2IsNull)
2838 : : {
2839 [ # # ]: 0 : if (TIMETZ_GT(ts2, te2))
2840 : : {
9175 bruce@momjian.us 2841 : 0 : Datum tt = ts2;
2842 : :
9280 tgl@sss.pgh.pa.us 2843 : 0 : ts2 = te2;
2844 : 0 : te2 = tt;
2845 : : }
2846 : : }
2847 : :
2848 : : /*
2849 : : * At this point neither ts1 nor ts2 is null, so we can consider three
2850 : : * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2
2851 : : */
2852 [ # # ]: 0 : if (TIMETZ_GT(ts1, ts2))
2853 : : {
2854 : : /*
2855 : : * This case is ts1 < te2 OR te1 < te2, which may look redundant but
2856 : : * in the presence of nulls it's not quite completely so.
2857 : : */
2858 [ # # ]: 0 : if (te2IsNull)
2859 : 0 : PG_RETURN_NULL();
2860 [ # # ]: 0 : if (TIMETZ_LT(ts1, te2))
2861 : 0 : PG_RETURN_BOOL(true);
2862 [ # # ]: 0 : if (te1IsNull)
2863 : 0 : PG_RETURN_NULL();
2864 : :
2865 : : /*
2866 : : * If te1 is not null then we had ts1 <= te1 above, and we just found
2867 : : * ts1 >= te2, hence te1 >= te2.
2868 : : */
2869 : 0 : PG_RETURN_BOOL(false);
2870 : : }
2871 [ # # ]: 0 : else if (TIMETZ_LT(ts1, ts2))
2872 : : {
2873 : : /* This case is ts2 < te1 OR te2 < te1 */
2874 [ # # ]: 0 : if (te1IsNull)
2875 : 0 : PG_RETURN_NULL();
2876 [ # # ]: 0 : if (TIMETZ_LT(ts2, te1))
2877 : 0 : PG_RETURN_BOOL(true);
2878 [ # # ]: 0 : if (te2IsNull)
2879 : 0 : PG_RETURN_NULL();
2880 : :
2881 : : /*
2882 : : * If te2 is not null then we had ts2 <= te2 above, and we just found
2883 : : * ts2 >= te1, hence te2 >= te1.
2884 : : */
2885 : 0 : PG_RETURN_BOOL(false);
2886 : : }
2887 : : else
2888 : : {
2889 : : /*
2890 : : * For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a
2891 : : * rather silly way of saying "true if both are nonnull, else null".
2892 : : */
2893 [ # # # # ]: 0 : if (te1IsNull || te2IsNull)
2894 : 0 : PG_RETURN_NULL();
2895 : 0 : PG_RETURN_BOOL(true);
2896 : : }
2897 : :
2898 : : #undef TIMETZ_GT
2899 : : #undef TIMETZ_LT
2900 : : }
2901 : :
2902 : :
2903 : : Datum
8985 lockhart@fourpalms.o 2904 :CBC 56 : timetz_time(PG_FUNCTION_ARGS)
2905 : : {
2906 : 56 : TimeTzADT *timetz = PG_GETARG_TIMETZADT_P(0);
2907 : : TimeADT result;
2908 : :
2909 : : /* swallow the time zone and just return the time */
2910 : 56 : result = timetz->time;
2911 : :
2912 : 56 : PG_RETURN_TIMEADT(result);
2913 : : }
2914 : :
2915 : :
2916 : : Datum
2917 : 208 : time_timetz(PG_FUNCTION_ARGS)
2918 : : {
2919 : 208 : TimeADT time = PG_GETARG_TIMEADT(0);
2920 : : TimeTzADT *result;
2921 : : struct pg_tm tt,
2922 : 208 : *tm = &tt;
2923 : : fsec_t fsec;
2924 : : int tz;
2925 : :
8729 JanWieck@Yahoo.com 2926 : 208 : GetCurrentDateTime(tm);
8780 lockhart@fourpalms.o 2927 : 208 : time2tm(time, tm, &fsec);
6849 tgl@sss.pgh.pa.us 2928 : 208 : tz = DetermineTimeZoneOffset(tm, session_timezone);
2929 : :
146 michael@paquier.xyz 2930 :GNC 208 : result = palloc_object(TimeTzADT);
2931 : :
8985 lockhart@fourpalms.o 2932 :CBC 208 : result->time = time;
2933 : 208 : result->zone = tz;
2934 : :
2935 : 208 : PG_RETURN_TIMETZADT_P(result);
2936 : : }
2937 : :
2938 : :
2939 : : /* timestamptz_timetz()
2940 : : * Convert timestamp to timetz data type.
2941 : : */
2942 : : Datum
2943 : 40 : timestamptz_timetz(PG_FUNCTION_ARGS)
2944 : : {
8958 bruce@momjian.us 2945 : 40 : TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
2946 : : TimeTzADT *result;
2947 : : struct pg_tm tt,
9548 lockhart@fourpalms.o 2948 : 40 : *tm = &tt;
2949 : : int tz;
2950 : : fsec_t fsec;
2951 : :
9461 tgl@sss.pgh.pa.us 2952 [ + - - + ]: 40 : if (TIMESTAMP_NOT_FINITE(timestamp))
8985 lockhart@fourpalms.o 2953 :UBC 0 : PG_RETURN_NULL();
2954 : :
5164 peter_e@gmx.net 2955 [ - + ]:CBC 40 : if (timestamp2tm(timestamp, &tz, tm, &fsec, NULL, NULL) != 0)
42 peter@eisentraut.org 2956 [ # # ]:UNC 0 : ereturn(fcinfo->context, (Datum) 0,
2957 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2958 : : errmsg("timestamp out of range")));
2959 : :
146 michael@paquier.xyz 2960 :GNC 40 : result = palloc_object(TimeTzADT);
2961 : :
8780 lockhart@fourpalms.o 2962 :CBC 40 : tm2timetz(tm, fsec, tz, result);
2963 : :
9461 tgl@sss.pgh.pa.us 2964 : 40 : PG_RETURN_TIMETZADT_P(result);
2965 : : }
2966 : :
2967 : :
2968 : : /* datetimetz_timestamptz()
2969 : : * Convert date and timetz to timestamp with time zone data type.
2970 : : * Timestamp is stored in GMT, so add the time zone
2971 : : * stored with the timetz to the result.
2972 : : * - thomas 2000-03-10
2973 : : */
2974 : : Datum
8985 lockhart@fourpalms.o 2975 : 45 : datetimetz_timestamptz(PG_FUNCTION_ARGS)
2976 : : {
7507 bruce@momjian.us 2977 : 45 : DateADT date = PG_GETARG_DATEADT(0);
9461 tgl@sss.pgh.pa.us 2978 : 45 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2979 : : TimestampTz result;
2980 : :
6412 2981 [ - + ]: 45 : if (DATE_IS_NOBEGIN(date))
6412 tgl@sss.pgh.pa.us 2982 :UBC 0 : TIMESTAMP_NOBEGIN(result);
6412 tgl@sss.pgh.pa.us 2983 [ - + ]:CBC 45 : else if (DATE_IS_NOEND(date))
6412 tgl@sss.pgh.pa.us 2984 :UBC 0 : TIMESTAMP_NOEND(result);
2985 : : else
2986 : : {
2987 : : /*
2988 : : * Date's range is wider than timestamp's, so check for boundaries.
2989 : : * Since dates have the same minimum values as timestamps, only upper
2990 : : * boundary need be checked for overflow.
2991 : : */
3702 tgl@sss.pgh.pa.us 2992 [ - + ]:CBC 45 : if (date >= (TIMESTAMP_END_JULIAN - POSTGRES_EPOCH_JDATE))
3702 tgl@sss.pgh.pa.us 2993 [ # # ]:UBC 0 : ereport(ERROR,
2994 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2995 : : errmsg("date out of range for timestamp")));
6412 tgl@sss.pgh.pa.us 2996 :CBC 45 : result = date * USECS_PER_DAY + time->time + time->zone * USECS_PER_SEC;
2997 : :
2998 : : /*
2999 : : * Since it is possible to go beyond allowed timestamptz range because
3000 : : * of time zone, check for allowed timestamp range after adding tz.
3001 : : */
3702 3002 [ + - - + ]: 45 : if (!IS_VALID_TIMESTAMP(result))
3702 tgl@sss.pgh.pa.us 3003 [ # # ]:UBC 0 : ereport(ERROR,
3004 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3005 : : errmsg("date out of range for timestamp")));
3006 : : }
3007 : :
9461 tgl@sss.pgh.pa.us 3008 :CBC 45 : PG_RETURN_TIMESTAMP(result);
3009 : : }
3010 : :
3011 : :
3012 : : /* timetz_part() and extract_timetz()
3013 : : * Extract specified field from time type.
3014 : : */
3015 : : static Datum
1855 peter@eisentraut.org 3016 : 73 : timetz_part_common(PG_FUNCTION_ARGS, bool retnumeric)
3017 : : {
6615 tgl@sss.pgh.pa.us 3018 : 73 : text *units = PG_GETARG_TEXT_PP(0);
8965 lockhart@fourpalms.o 3019 : 73 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
3020 : : int64 intresult;
3021 : : int type,
3022 : : val;
3023 : : char *lowunits;
3024 : :
6615 tgl@sss.pgh.pa.us 3025 [ - + ]: 73 : lowunits = downcase_truncate_identifier(VARDATA_ANY(units),
3026 [ - + - - : 73 : VARSIZE_ANY_EXHDR(units),
- - - - -
+ ]
3027 : : false);
3028 : :
8965 lockhart@fourpalms.o 3029 : 73 : type = DecodeUnits(0, lowunits, &val);
3030 [ + + ]: 73 : if (type == UNKNOWN_FIELD)
3031 : 14 : type = DecodeSpecial(0, lowunits, &val);
3032 : :
3033 [ + + ]: 73 : if (type == UNITS)
3034 : : {
3035 : : int tz;
3036 : : fsec_t fsec;
3037 : : struct pg_tm tt,
3038 : 59 : *tm = &tt;
3039 : :
8780 3040 : 59 : timetz2tm(time, tm, &fsec, &tz);
3041 : :
8965 3042 [ + + + + : 59 : switch (val)
+ + + +
+ ]
3043 : : {
3044 : 5 : case DTK_TZ:
1855 peter@eisentraut.org 3045 : 5 : intresult = -tz;
8965 lockhart@fourpalms.o 3046 : 5 : break;
3047 : :
3048 : 5 : case DTK_TZ_MINUTE:
1855 peter@eisentraut.org 3049 : 5 : intresult = (-tz / SECS_PER_MINUTE) % MINS_PER_HOUR;
8965 lockhart@fourpalms.o 3050 : 5 : break;
3051 : :
3052 : 5 : case DTK_TZ_HOUR:
1855 peter@eisentraut.org 3053 : 5 : intresult = -tz / SECS_PER_HOUR;
8965 lockhart@fourpalms.o 3054 : 5 : break;
3055 : :
3056 : 10 : case DTK_MICROSEC:
1850 tgl@sss.pgh.pa.us 3057 : 10 : intresult = tm->tm_sec * INT64CONST(1000000) + fsec;
8965 lockhart@fourpalms.o 3058 : 10 : break;
3059 : :
3060 : 10 : case DTK_MILLISEC:
1855 peter@eisentraut.org 3061 [ + + ]: 10 : if (retnumeric)
3062 : : /*---
3063 : : * tm->tm_sec * 1000 + fsec / 1000
3064 : : * = (tm->tm_sec * 1'000'000 + fsec) / 1000
3065 : : */
1850 tgl@sss.pgh.pa.us 3066 : 20 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 3));
3067 : : else
1855 peter@eisentraut.org 3068 : 5 : PG_RETURN_FLOAT8(tm->tm_sec * 1000.0 + fsec / 1000.0);
3069 : : break;
3070 : :
8965 lockhart@fourpalms.o 3071 : 10 : case DTK_SECOND:
1855 peter@eisentraut.org 3072 [ + + ]: 10 : if (retnumeric)
3073 : : /*---
3074 : : * tm->tm_sec + fsec / 1'000'000
3075 : : * = (tm->tm_sec * 1'000'000 + fsec) / 1'000'000
3076 : : */
1850 tgl@sss.pgh.pa.us 3077 : 5 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(tm->tm_sec * INT64CONST(1000000) + fsec, 6));
3078 : : else
1855 peter@eisentraut.org 3079 : 5 : PG_RETURN_FLOAT8(tm->tm_sec + fsec / 1000000.0);
3080 : : break;
3081 : :
8965 lockhart@fourpalms.o 3082 : 5 : case DTK_MINUTE:
1855 peter@eisentraut.org 3083 : 5 : intresult = tm->tm_min;
8965 lockhart@fourpalms.o 3084 : 5 : break;
3085 : :
3086 : 5 : case DTK_HOUR:
1855 peter@eisentraut.org 3087 : 5 : intresult = tm->tm_hour;
8965 lockhart@fourpalms.o 3088 : 5 : break;
3089 : :
3090 : 4 : case DTK_DAY:
3091 : : case DTK_MONTH:
3092 : : case DTK_QUARTER:
3093 : : case DTK_YEAR:
3094 : : case DTK_DECADE:
3095 : : case DTK_CENTURY:
3096 : : case DTK_MILLENNIUM:
3097 : : default:
8318 tgl@sss.pgh.pa.us 3098 [ + - ]: 4 : ereport(ERROR,
3099 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3100 : : errmsg("unit \"%s\" not supported for type %s",
3101 : : lowunits, format_type_be(TIMETZOID))));
3102 : : intresult = 0;
3103 : : }
3104 : : }
7651 bruce@momjian.us 3105 [ + + + - ]: 14 : else if (type == RESERV && val == DTK_EPOCH)
3106 : : {
1855 peter@eisentraut.org 3107 [ + + ]: 10 : if (retnumeric)
3108 : : /*---
3109 : : * time->time / 1'000'000 + time->zone
3110 : : * = (time->time + time->zone * 1'000'000) / 1'000'000
3111 : : */
1850 tgl@sss.pgh.pa.us 3112 : 5 : PG_RETURN_NUMERIC(int64_div_fast_to_numeric(time->time + time->zone * INT64CONST(1000000), 6));
3113 : : else
1855 peter@eisentraut.org 3114 : 5 : PG_RETURN_FLOAT8(time->time / 1000000.0 + time->zone);
3115 : : }
3116 : : else
3117 : : {
8318 tgl@sss.pgh.pa.us 3118 [ + - ]: 4 : ereport(ERROR,
3119 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3120 : : errmsg("unit \"%s\" not recognized for type %s",
3121 : : lowunits, format_type_be(TIMETZOID))));
3122 : : intresult = 0;
3123 : : }
3124 : :
1855 peter@eisentraut.org 3125 [ + + ]: 35 : if (retnumeric)
3126 : 30 : PG_RETURN_NUMERIC(int64_to_numeric(intresult));
3127 : : else
3128 : 5 : PG_RETURN_FLOAT8(intresult);
3129 : : }
3130 : :
3131 : :
3132 : : Datum
3133 : 20 : timetz_part(PG_FUNCTION_ARGS)
3134 : : {
3135 : 20 : return timetz_part_common(fcinfo, false);
3136 : : }
3137 : :
3138 : : Datum
3139 : 53 : extract_timetz(PG_FUNCTION_ARGS)
3140 : : {
3141 : 53 : return timetz_part_common(fcinfo, true);
3142 : : }
3143 : :
3144 : : /* timetz_zone()
3145 : : * Encode time with time zone type with specified time zone.
3146 : : * Applies DST rules as of the transaction start time.
3147 : : */
3148 : : Datum
8985 lockhart@fourpalms.o 3149 : 192 : timetz_zone(PG_FUNCTION_ARGS)
3150 : : {
6615 tgl@sss.pgh.pa.us 3151 : 192 : text *zone = PG_GETARG_TEXT_PP(0);
7629 bruce@momjian.us 3152 : 192 : TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
3153 : : TimeTzADT *result;
3154 : : int tz;
3155 : : char tzname[TZ_STRLEN_MAX + 1];
3156 : : int type,
3157 : : val;
3158 : : pg_tz *tzp;
3159 : :
3160 : : /*
3161 : : * Look up the requested timezone.
3162 : : */
6615 tgl@sss.pgh.pa.us 3163 : 192 : text_to_cstring_buffer(zone, tzname, sizeof(tzname));
3164 : :
1145 3165 : 192 : type = DecodeTimezoneName(tzname, &val, &tzp);
3166 : :
3167 [ + + ]: 192 : if (type == TZNAME_FIXED_OFFSET)
3168 : : {
3169 : : /* fixed-offset abbreviation */
4219 3170 : 144 : tz = -val;
3171 : : }
1145 3172 [ - + ]: 48 : else if (type == TZNAME_DYNTZ)
3173 : : {
3174 : : /* dynamic-offset abbreviation, resolve using transaction start time */
1702 tgl@sss.pgh.pa.us 3175 :UBC 0 : TimestampTz now = GetCurrentTransactionStartTimestamp();
3176 : : int isdst;
3177 : :
3178 : 0 : tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
3179 : : }
3180 : : else
3181 : : {
3182 : : /* Get the offset-from-GMT that is valid now for the zone name */
1145 tgl@sss.pgh.pa.us 3183 :CBC 48 : TimestampTz now = GetCurrentTransactionStartTimestamp();
3184 : : struct pg_tm tm;
3185 : : fsec_t fsec;
3186 : :
3187 [ - + ]: 48 : if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
7543 tgl@sss.pgh.pa.us 3188 [ # # ]:UBC 0 : ereport(ERROR,
3189 : : (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3190 : : errmsg("timestamp out of range")));
3191 : : }
3192 : :
146 michael@paquier.xyz 3193 :GNC 192 : result = palloc_object(TimeTzADT);
3194 : :
7629 bruce@momjian.us 3195 :CBC 192 : result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
3196 : : /* C99 modulo has the wrong sign convention for negative input */
3197 [ + + ]: 204 : while (result->time < INT64CONST(0))
3198 : 12 : result->time += USECS_PER_DAY;
931 tgl@sss.pgh.pa.us 3199 [ + + ]: 192 : if (result->time >= USECS_PER_DAY)
3200 : 24 : result->time %= USECS_PER_DAY;
3201 : :
7629 bruce@momjian.us 3202 : 192 : result->zone = tz;
3203 : :
8985 lockhart@fourpalms.o 3204 : 192 : PG_RETURN_TIMETZADT_P(result);
3205 : : }
3206 : :
3207 : : /* timetz_izone()
3208 : : * Encode time with time zone type with specified time interval as time zone.
3209 : : */
3210 : : Datum
3211 : 112 : timetz_izone(PG_FUNCTION_ARGS)
3212 : : {
3213 : 112 : Interval *zone = PG_GETARG_INTERVAL_P(0);
3214 : 112 : TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
3215 : : TimeTzADT *result;
3216 : : int tz;
3217 : :
903 dean.a.rasheed@gmail 3218 [ + + + - : 112 : if (INTERVAL_NOT_FINITE(zone))
- + + + +
- + - ]
3219 [ + - ]: 16 : ereport(ERROR,
3220 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3221 : : errmsg("interval time zone \"%s\" must be finite",
3222 : : DatumGetCString(DirectFunctionCall1(interval_out,
3223 : : PointerGetDatum(zone))))));
3224 : :
4842 tgl@sss.pgh.pa.us 3225 [ + - - + ]: 96 : if (zone->month != 0 || zone->day != 0)
8318 tgl@sss.pgh.pa.us 3226 [ # # ]:UBC 0 : ereport(ERROR,
3227 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3228 : : errmsg("interval time zone \"%s\" must not include months or days",
3229 : : DatumGetCString(DirectFunctionCall1(interval_out,
3230 : : PointerGetDatum(zone))))));
3231 : :
7652 bruce@momjian.us 3232 :CBC 96 : tz = -(zone->time / USECS_PER_SEC);
3233 : :
146 michael@paquier.xyz 3234 :GNC 96 : result = palloc_object(TimeTzADT);
3235 : :
7651 bruce@momjian.us 3236 :CBC 96 : result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
3237 : : /* C99 modulo has the wrong sign convention for negative input */
8780 lockhart@fourpalms.o 3238 [ + + ]: 108 : while (result->time < INT64CONST(0))
7652 bruce@momjian.us 3239 : 12 : result->time += USECS_PER_DAY;
931 tgl@sss.pgh.pa.us 3240 [ + + ]: 96 : if (result->time >= USECS_PER_DAY)
3241 : 8 : result->time %= USECS_PER_DAY;
3242 : :
8985 lockhart@fourpalms.o 3243 : 96 : result->zone = tz;
3244 : :
3245 : 96 : PG_RETURN_TIMETZADT_P(result);
3246 : : }
3247 : :
3248 : : /* timetz_at_local()
3249 : : *
3250 : : * Unlike for timestamp[tz]_at_local, the type for timetz does not flip between
3251 : : * time with/without time zone, so we cannot just call the conversion function.
3252 : : */
3253 : : Datum
935 michael@paquier.xyz 3254 : 96 : timetz_at_local(PG_FUNCTION_ARGS)
3255 : : {
3256 : 96 : Datum time = PG_GETARG_DATUM(0);
3257 : 96 : const char *tzn = pg_get_timezone_name(session_timezone);
3258 : 96 : Datum zone = PointerGetDatum(cstring_to_text(tzn));
3259 : :
3260 : 96 : return DirectFunctionCall2(timetz_zone, zone, time);
3261 : : }
|