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