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