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