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