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