1 /*-------------------------------------------------------------------------
2  *
3  * nabstime.c
4  *	  Utilities for the built-in type "AbsoluteTime".
5  *	  Functions for the built-in type "RelativeTime".
6  *	  Functions for the built-in type "TimeInterval".
7  *
8  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *	  src/backend/utils/adt/nabstime.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18 
19 #include <ctype.h>
20 #include <float.h>
21 #include <limits.h>
22 #include <math.h>
23 #include <time.h>
24 #include <sys/time.h>
25 
26 #include "libpq/pqformat.h"
27 #include "miscadmin.h"
28 #include "utils/builtins.h"
29 #include "utils/datetime.h"
30 #include "utils/nabstime.h"
31 
32 #define MIN_DAYNUM (-24856)		/* December 13, 1901 */
33 #define MAX_DAYNUM 24854		/* January 18, 2038 */
34 
35 /*
36  * Unix epoch is Jan  1 00:00:00 1970.
37  * Postgres knows about times sixty-eight years on either side of that
38  * for these 4-byte types.
39  *
40  * "tinterval" is two 4-byte fields.
41  * Definitions for parsing tinterval.
42  */
43 
44 #define IsSpace(C)				((C) == ' ')
45 
46 #define T_INTERVAL_INVAL   0	/* data represents no valid tinterval */
47 #define T_INTERVAL_VALID   1	/* data represents a valid tinterval */
48 /*
49  * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
50  * 0		1		  2			3		  4			5		  6
51  * 1234567890123456789012345678901234567890123456789012345678901234
52  *
53  * we allocate some extra -- timezones are usually 3 characters but
54  * this is not in the POSIX standard...
55  */
56 #define T_INTERVAL_LEN					80
57 #define INVALID_INTERVAL_STR			"Undefined Range"
58 #define INVALID_INTERVAL_STR_LEN		(sizeof(INVALID_INTERVAL_STR)-1)
59 
60 #define ABSTIMEMIN(t1, t2) \
61 	(DatumGetBool(DirectFunctionCall2(abstimele, \
62 				  AbsoluteTimeGetDatum(t1), \
63 				  AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
64 #define ABSTIMEMAX(t1, t2) \
65 	(DatumGetBool(DirectFunctionCall2(abstimelt, \
66 				  AbsoluteTimeGetDatum(t1), \
67 				  AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
68 
69 
70 /*
71  * Function prototypes -- internal to this file only
72  */
73 
74 static AbsoluteTime tm2abstime(struct pg_tm *tm, int tz);
75 static void reltime2tm(RelativeTime time, struct pg_tm *tm);
76 static void parsetinterval(char *i_string,
77 			   AbsoluteTime *i_start,
78 			   AbsoluteTime *i_end);
79 
80 
81 /*
82  * GetCurrentAbsoluteTime()
83  *
84  * Get the current system time (relative to Unix epoch).
85  *
86  * NB: this will overflow in 2038; it should be gone long before that.
87  */
88 AbsoluteTime
GetCurrentAbsoluteTime(void)89 GetCurrentAbsoluteTime(void)
90 {
91 	time_t		now;
92 
93 	now = time(NULL);
94 	return (AbsoluteTime) now;
95 }
96 
97 
98 void
abstime2tm(AbsoluteTime _time,int * tzp,struct pg_tm * tm,char ** tzn)99 abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm *tm, char **tzn)
100 {
101 	pg_time_t	time = (pg_time_t) _time;
102 	struct pg_tm *tx;
103 
104 	if (tzp != NULL)
105 		tx = pg_localtime(&time, session_timezone);
106 	else
107 		tx = pg_gmtime(&time);
108 
109 	if (tx == NULL)
110 		elog(ERROR, "could not convert abstime to timestamp: %m");
111 
112 	tm->tm_year = tx->tm_year + 1900;
113 	tm->tm_mon = tx->tm_mon + 1;
114 	tm->tm_mday = tx->tm_mday;
115 	tm->tm_hour = tx->tm_hour;
116 	tm->tm_min = tx->tm_min;
117 	tm->tm_sec = tx->tm_sec;
118 	tm->tm_isdst = tx->tm_isdst;
119 
120 	tm->tm_gmtoff = tx->tm_gmtoff;
121 	tm->tm_zone = tx->tm_zone;
122 
123 	if (tzp != NULL)
124 	{
125 		*tzp = -tm->tm_gmtoff;	/* tm_gmtoff is Sun/DEC-ism */
126 
127 		/*
128 		 * XXX FreeBSD man pages indicate that this should work - tgl 97/04/23
129 		 */
130 		if (tzn != NULL)
131 		{
132 			/*
133 			 * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
134 			 * contains an error message, which doesn't fit in the buffer
135 			 */
136 			StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
137 			if (strlen(tm->tm_zone) > MAXTZLEN)
138 				ereport(WARNING,
139 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
140 						 errmsg("invalid time zone name: \"%s\"",
141 								tm->tm_zone)));
142 		}
143 	}
144 	else
145 		tm->tm_isdst = -1;
146 }
147 
148 
149 /* tm2abstime()
150  * Convert a tm structure to abstime.
151  * Note that tm has full year (not 1900-based) and 1-based month.
152  */
153 static AbsoluteTime
tm2abstime(struct pg_tm * tm,int tz)154 tm2abstime(struct pg_tm *tm, int tz)
155 {
156 	int			day;
157 	AbsoluteTime sec;
158 
159 	/* validate, before going out of range on some members */
160 	if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
161 		tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
162 		tm->tm_mday < 1 || tm->tm_mday > 31 ||
163 		tm->tm_hour < 0 ||
164 		tm->tm_hour > HOURS_PER_DAY ||	/* test for > 24:00:00 */
165 		(tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
166 		tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
167 		tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
168 		return INVALID_ABSTIME;
169 
170 	day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
171 
172 	/* check for time out of range */
173 	if (day < MIN_DAYNUM || day > MAX_DAYNUM)
174 		return INVALID_ABSTIME;
175 
176 	/* convert to seconds */
177 	sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE;
178 
179 	/*
180 	 * check for overflow.  We need a little slop here because the H/M/S plus
181 	 * TZ offset could add up to more than 1 day.
182 	 */
183 	if ((day >= MAX_DAYNUM - 10 && sec < 0) ||
184 		(day <= MIN_DAYNUM + 10 && sec > 0))
185 		return INVALID_ABSTIME;
186 
187 	/* check for reserved values (e.g. "current" on edge of usual range */
188 	if (!AbsoluteTimeIsReal(sec))
189 		return INVALID_ABSTIME;
190 
191 	return sec;
192 }
193 
194 
195 /* abstimein()
196  * Decode date/time string and return abstime.
197  */
198 Datum
abstimein(PG_FUNCTION_ARGS)199 abstimein(PG_FUNCTION_ARGS)
200 {
201 	char	   *str = PG_GETARG_CSTRING(0);
202 	AbsoluteTime result;
203 	fsec_t		fsec;
204 	int			tz = 0;
205 	struct pg_tm date,
206 			   *tm = &date;
207 	int			dterr;
208 	char	   *field[MAXDATEFIELDS];
209 	char		workbuf[MAXDATELEN + 1];
210 	int			dtype;
211 	int			nf,
212 				ftype[MAXDATEFIELDS];
213 
214 	dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
215 						  field, ftype, MAXDATEFIELDS, &nf);
216 	if (dterr == 0)
217 		dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
218 	if (dterr != 0)
219 		DateTimeParseError(dterr, str, "abstime");
220 
221 	switch (dtype)
222 	{
223 		case DTK_DATE:
224 			result = tm2abstime(tm, tz);
225 			break;
226 
227 		case DTK_EPOCH:
228 
229 			/*
230 			 * Don't bother retaining this as a reserved value, but instead
231 			 * just set to the actual epoch time (1970-01-01)
232 			 */
233 			result = 0;
234 			break;
235 
236 		case DTK_LATE:
237 			result = NOEND_ABSTIME;
238 			break;
239 
240 		case DTK_EARLY:
241 			result = NOSTART_ABSTIME;
242 			break;
243 
244 		case DTK_INVALID:
245 			result = INVALID_ABSTIME;
246 			break;
247 
248 		default:
249 			elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
250 				 dtype, str);
251 			result = INVALID_ABSTIME;
252 			break;
253 	};
254 
255 	PG_RETURN_ABSOLUTETIME(result);
256 }
257 
258 
259 /* abstimeout()
260  * Given an AbsoluteTime return the English text version of the date
261  */
262 Datum
abstimeout(PG_FUNCTION_ARGS)263 abstimeout(PG_FUNCTION_ARGS)
264 {
265 	AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
266 	char	   *result;
267 	int			tz;
268 	double		fsec = 0;
269 	struct pg_tm tt,
270 			   *tm = &tt;
271 	char		buf[MAXDATELEN + 1];
272 	char		zone[MAXDATELEN + 1],
273 			   *tzn = zone;
274 
275 	switch (time)
276 	{
277 			/*
278 			 * Note that timestamp no longer supports 'invalid'. Retain
279 			 * 'invalid' for abstime for now, but dump it someday.
280 			 */
281 		case INVALID_ABSTIME:
282 			strcpy(buf, INVALID);
283 			break;
284 		case NOEND_ABSTIME:
285 			strcpy(buf, LATE);
286 			break;
287 		case NOSTART_ABSTIME:
288 			strcpy(buf, EARLY);
289 			break;
290 		default:
291 			abstime2tm(time, &tz, tm, &tzn);
292 			EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
293 			break;
294 	}
295 
296 	result = pstrdup(buf);
297 	PG_RETURN_CSTRING(result);
298 }
299 
300 /*
301  *		abstimerecv			- converts external binary format to abstime
302  */
303 Datum
abstimerecv(PG_FUNCTION_ARGS)304 abstimerecv(PG_FUNCTION_ARGS)
305 {
306 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
307 
308 	PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
309 }
310 
311 /*
312  *		abstimesend			- converts abstime to binary format
313  */
314 Datum
abstimesend(PG_FUNCTION_ARGS)315 abstimesend(PG_FUNCTION_ARGS)
316 {
317 	AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
318 	StringInfoData buf;
319 
320 	pq_begintypsend(&buf);
321 	pq_sendint32(&buf, time);
322 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
323 }
324 
325 
326 /* abstime_finite()
327  */
328 Datum
abstime_finite(PG_FUNCTION_ARGS)329 abstime_finite(PG_FUNCTION_ARGS)
330 {
331 	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
332 
333 	PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
334 				   abstime != NOSTART_ABSTIME &&
335 				   abstime != NOEND_ABSTIME);
336 }
337 
338 
339 /*
340  * abstime comparison routines
341  */
342 static int
abstime_cmp_internal(AbsoluteTime a,AbsoluteTime b)343 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
344 {
345 	/*
346 	 * We consider all INVALIDs to be equal and larger than any non-INVALID.
347 	 * This is somewhat arbitrary; the important thing is to have a consistent
348 	 * sort order.
349 	 */
350 	if (a == INVALID_ABSTIME)
351 	{
352 		if (b == INVALID_ABSTIME)
353 			return 0;			/* INVALID = INVALID */
354 		else
355 			return 1;			/* INVALID > non-INVALID */
356 	}
357 
358 	if (b == INVALID_ABSTIME)
359 		return -1;				/* non-INVALID < INVALID */
360 
361 	if (a > b)
362 		return 1;
363 	else if (a == b)
364 		return 0;
365 	else
366 		return -1;
367 }
368 
369 Datum
abstimeeq(PG_FUNCTION_ARGS)370 abstimeeq(PG_FUNCTION_ARGS)
371 {
372 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
373 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
374 
375 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
376 }
377 
378 Datum
abstimene(PG_FUNCTION_ARGS)379 abstimene(PG_FUNCTION_ARGS)
380 {
381 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
382 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
383 
384 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
385 }
386 
387 Datum
abstimelt(PG_FUNCTION_ARGS)388 abstimelt(PG_FUNCTION_ARGS)
389 {
390 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
391 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
392 
393 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
394 }
395 
396 Datum
abstimegt(PG_FUNCTION_ARGS)397 abstimegt(PG_FUNCTION_ARGS)
398 {
399 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
400 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
401 
402 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
403 }
404 
405 Datum
abstimele(PG_FUNCTION_ARGS)406 abstimele(PG_FUNCTION_ARGS)
407 {
408 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
409 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
410 
411 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
412 }
413 
414 Datum
abstimege(PG_FUNCTION_ARGS)415 abstimege(PG_FUNCTION_ARGS)
416 {
417 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
418 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
419 
420 	PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
421 }
422 
423 Datum
btabstimecmp(PG_FUNCTION_ARGS)424 btabstimecmp(PG_FUNCTION_ARGS)
425 {
426 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
427 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
428 
429 	PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
430 }
431 
432 
433 /* timestamp_abstime()
434  * Convert timestamp to abstime.
435  */
436 Datum
timestamp_abstime(PG_FUNCTION_ARGS)437 timestamp_abstime(PG_FUNCTION_ARGS)
438 {
439 	Timestamp	timestamp = PG_GETARG_TIMESTAMP(0);
440 	AbsoluteTime result;
441 	fsec_t		fsec;
442 	int			tz;
443 	struct pg_tm tt,
444 			   *tm = &tt;
445 
446 	if (TIMESTAMP_IS_NOBEGIN(timestamp))
447 		result = NOSTART_ABSTIME;
448 	else if (TIMESTAMP_IS_NOEND(timestamp))
449 		result = NOEND_ABSTIME;
450 	else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
451 	{
452 		tz = DetermineTimeZoneOffset(tm, session_timezone);
453 		result = tm2abstime(tm, tz);
454 	}
455 	else
456 	{
457 		ereport(ERROR,
458 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
459 				 errmsg("timestamp out of range")));
460 		result = INVALID_ABSTIME;
461 	}
462 
463 	PG_RETURN_ABSOLUTETIME(result);
464 }
465 
466 /* abstime_timestamp()
467  * Convert abstime to timestamp.
468  */
469 Datum
abstime_timestamp(PG_FUNCTION_ARGS)470 abstime_timestamp(PG_FUNCTION_ARGS)
471 {
472 	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
473 	Timestamp	result;
474 	struct pg_tm tt,
475 			   *tm = &tt;
476 	int			tz;
477 	char		zone[MAXDATELEN + 1],
478 			   *tzn = zone;
479 
480 	switch (abstime)
481 	{
482 		case INVALID_ABSTIME:
483 			ereport(ERROR,
484 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
485 					 errmsg("cannot convert abstime \"invalid\" to timestamp")));
486 			TIMESTAMP_NOBEGIN(result);
487 			break;
488 
489 		case NOSTART_ABSTIME:
490 			TIMESTAMP_NOBEGIN(result);
491 			break;
492 
493 		case NOEND_ABSTIME:
494 			TIMESTAMP_NOEND(result);
495 			break;
496 
497 		default:
498 			abstime2tm(abstime, &tz, tm, &tzn);
499 			if (tm2timestamp(tm, 0, NULL, &result) != 0)
500 				ereport(ERROR,
501 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
502 						 errmsg("timestamp out of range")));
503 			break;
504 	};
505 
506 	PG_RETURN_TIMESTAMP(result);
507 }
508 
509 
510 /* timestamptz_abstime()
511  * Convert timestamp with time zone to abstime.
512  */
513 Datum
timestamptz_abstime(PG_FUNCTION_ARGS)514 timestamptz_abstime(PG_FUNCTION_ARGS)
515 {
516 	TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
517 	AbsoluteTime result;
518 	fsec_t		fsec;
519 	struct pg_tm tt,
520 			   *tm = &tt;
521 
522 	if (TIMESTAMP_IS_NOBEGIN(timestamp))
523 		result = NOSTART_ABSTIME;
524 	else if (TIMESTAMP_IS_NOEND(timestamp))
525 		result = NOEND_ABSTIME;
526 	else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
527 		result = tm2abstime(tm, 0);
528 	else
529 	{
530 		ereport(ERROR,
531 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
532 				 errmsg("timestamp out of range")));
533 		result = INVALID_ABSTIME;
534 	}
535 
536 	PG_RETURN_ABSOLUTETIME(result);
537 }
538 
539 /* abstime_timestamptz()
540  * Convert abstime to timestamp with time zone.
541  */
542 Datum
abstime_timestamptz(PG_FUNCTION_ARGS)543 abstime_timestamptz(PG_FUNCTION_ARGS)
544 {
545 	AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
546 	TimestampTz result;
547 	struct pg_tm tt,
548 			   *tm = &tt;
549 	int			tz;
550 	char		zone[MAXDATELEN + 1],
551 			   *tzn = zone;
552 
553 	switch (abstime)
554 	{
555 		case INVALID_ABSTIME:
556 			ereport(ERROR,
557 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
558 					 errmsg("cannot convert abstime \"invalid\" to timestamp")));
559 			TIMESTAMP_NOBEGIN(result);
560 			break;
561 
562 		case NOSTART_ABSTIME:
563 			TIMESTAMP_NOBEGIN(result);
564 			break;
565 
566 		case NOEND_ABSTIME:
567 			TIMESTAMP_NOEND(result);
568 			break;
569 
570 		default:
571 			abstime2tm(abstime, &tz, tm, &tzn);
572 			if (tm2timestamp(tm, 0, &tz, &result) != 0)
573 				ereport(ERROR,
574 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
575 						 errmsg("timestamp out of range")));
576 			break;
577 	};
578 
579 	PG_RETURN_TIMESTAMP(result);
580 }
581 
582 
583 /*****************************************************************************
584  *	 USER I/O ROUTINES														 *
585  *****************************************************************************/
586 
587 /*
588  *		reltimein		- converts a reltime string in an internal format
589  */
590 Datum
reltimein(PG_FUNCTION_ARGS)591 reltimein(PG_FUNCTION_ARGS)
592 {
593 	char	   *str = PG_GETARG_CSTRING(0);
594 	RelativeTime result;
595 	struct pg_tm tt,
596 			   *tm = &tt;
597 	fsec_t		fsec;
598 	int			dtype;
599 	int			dterr;
600 	char	   *field[MAXDATEFIELDS];
601 	int			nf,
602 				ftype[MAXDATEFIELDS];
603 	char		workbuf[MAXDATELEN + 1];
604 
605 	dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
606 						  field, ftype, MAXDATEFIELDS, &nf);
607 	if (dterr == 0)
608 		dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
609 							   &dtype, tm, &fsec);
610 
611 	/* if those functions think it's a bad format, try ISO8601 style */
612 	if (dterr == DTERR_BAD_FORMAT)
613 		dterr = DecodeISO8601Interval(str,
614 									  &dtype, tm, &fsec);
615 
616 	if (dterr != 0)
617 	{
618 		if (dterr == DTERR_FIELD_OVERFLOW)
619 			dterr = DTERR_INTERVAL_OVERFLOW;
620 		DateTimeParseError(dterr, str, "reltime");
621 	}
622 
623 	switch (dtype)
624 	{
625 		case DTK_DELTA:
626 			result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec;
627 			result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY;
628 			break;
629 
630 		default:
631 			elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
632 				 dtype, str);
633 			result = INVALID_RELTIME;
634 			break;
635 	}
636 
637 	PG_RETURN_RELATIVETIME(result);
638 }
639 
640 /*
641  *		reltimeout		- converts the internal format to a reltime string
642  */
643 Datum
reltimeout(PG_FUNCTION_ARGS)644 reltimeout(PG_FUNCTION_ARGS)
645 {
646 	RelativeTime time = PG_GETARG_RELATIVETIME(0);
647 	char	   *result;
648 	struct pg_tm tt,
649 			   *tm = &tt;
650 	char		buf[MAXDATELEN + 1];
651 
652 	reltime2tm(time, tm);
653 	EncodeInterval(tm, 0, IntervalStyle, buf);
654 
655 	result = pstrdup(buf);
656 	PG_RETURN_CSTRING(result);
657 }
658 
659 /*
660  *		reltimerecv			- converts external binary format to reltime
661  */
662 Datum
reltimerecv(PG_FUNCTION_ARGS)663 reltimerecv(PG_FUNCTION_ARGS)
664 {
665 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
666 
667 	PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
668 }
669 
670 /*
671  *		reltimesend			- converts reltime to binary format
672  */
673 Datum
reltimesend(PG_FUNCTION_ARGS)674 reltimesend(PG_FUNCTION_ARGS)
675 {
676 	RelativeTime time = PG_GETARG_RELATIVETIME(0);
677 	StringInfoData buf;
678 
679 	pq_begintypsend(&buf);
680 	pq_sendint32(&buf, time);
681 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
682 }
683 
684 
685 static void
reltime2tm(RelativeTime time,struct pg_tm * tm)686 reltime2tm(RelativeTime time, struct pg_tm *tm)
687 {
688 	double		dtime = time;
689 
690 	FMODULO(dtime, tm->tm_year, 31557600);
691 	FMODULO(dtime, tm->tm_mon, 2592000);
692 	FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
693 	FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR);
694 	FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE);
695 	FMODULO(dtime, tm->tm_sec, 1);
696 }
697 
698 
699 /*
700  *		tintervalin		- converts a tinterval string to internal format
701  */
702 Datum
tintervalin(PG_FUNCTION_ARGS)703 tintervalin(PG_FUNCTION_ARGS)
704 {
705 	char	   *tintervalstr = PG_GETARG_CSTRING(0);
706 	TimeInterval tinterval;
707 	AbsoluteTime i_start,
708 				i_end,
709 				t1,
710 				t2;
711 
712 	parsetinterval(tintervalstr, &t1, &t2);
713 
714 	tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
715 
716 	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
717 		tinterval->status = T_INTERVAL_INVAL;	/* undefined  */
718 	else
719 		tinterval->status = T_INTERVAL_VALID;
720 
721 	i_start = ABSTIMEMIN(t1, t2);
722 	i_end = ABSTIMEMAX(t1, t2);
723 	tinterval->data[0] = i_start;
724 	tinterval->data[1] = i_end;
725 
726 	PG_RETURN_TIMEINTERVAL(tinterval);
727 }
728 
729 
730 /*
731  *		tintervalout	- converts an internal tinterval format to a string
732  */
733 Datum
tintervalout(PG_FUNCTION_ARGS)734 tintervalout(PG_FUNCTION_ARGS)
735 {
736 	TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
737 	char	   *i_str,
738 			   *p;
739 
740 	i_str = (char *) palloc(T_INTERVAL_LEN);	/* ["..." "..."] */
741 	strcpy(i_str, "[\"");
742 	if (tinterval->status == T_INTERVAL_INVAL)
743 		strcat(i_str, INVALID_INTERVAL_STR);
744 	else
745 	{
746 		p = DatumGetCString(DirectFunctionCall1(abstimeout,
747 												AbsoluteTimeGetDatum(tinterval->data[0])));
748 		strcat(i_str, p);
749 		pfree(p);
750 		strcat(i_str, "\" \"");
751 		p = DatumGetCString(DirectFunctionCall1(abstimeout,
752 												AbsoluteTimeGetDatum(tinterval->data[1])));
753 		strcat(i_str, p);
754 		pfree(p);
755 	}
756 	strcat(i_str, "\"]");
757 	PG_RETURN_CSTRING(i_str);
758 }
759 
760 /*
761  *		tintervalrecv			- converts external binary format to tinterval
762  */
763 Datum
tintervalrecv(PG_FUNCTION_ARGS)764 tintervalrecv(PG_FUNCTION_ARGS)
765 {
766 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
767 	TimeInterval tinterval;
768 	int32		status;
769 
770 	tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
771 
772 	tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
773 	tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
774 	tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
775 
776 	if (tinterval->data[0] == INVALID_ABSTIME ||
777 		tinterval->data[1] == INVALID_ABSTIME)
778 		status = T_INTERVAL_INVAL;	/* undefined  */
779 	else
780 		status = T_INTERVAL_VALID;
781 
782 	if (status != tinterval->status)
783 		ereport(ERROR,
784 				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
785 				 errmsg("invalid status in external \"tinterval\" value")));
786 
787 	PG_RETURN_TIMEINTERVAL(tinterval);
788 }
789 
790 /*
791  *		tintervalsend			- converts tinterval to binary format
792  */
793 Datum
tintervalsend(PG_FUNCTION_ARGS)794 tintervalsend(PG_FUNCTION_ARGS)
795 {
796 	TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
797 	StringInfoData buf;
798 
799 	pq_begintypsend(&buf);
800 	pq_sendint32(&buf, tinterval->status);
801 	pq_sendint32(&buf, tinterval->data[0]);
802 	pq_sendint32(&buf, tinterval->data[1]);
803 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
804 }
805 
806 
807 /*****************************************************************************
808  *	 PUBLIC ROUTINES														 *
809  *****************************************************************************/
810 
811 Datum
interval_reltime(PG_FUNCTION_ARGS)812 interval_reltime(PG_FUNCTION_ARGS)
813 {
814 	Interval   *interval = PG_GETARG_INTERVAL_P(0);
815 	RelativeTime time;
816 	int			year,
817 				month,
818 				day;
819 	TimeOffset	span;
820 
821 	year = interval->month / MONTHS_PER_YEAR;
822 	month = interval->month % MONTHS_PER_YEAR;
823 	day = interval->day;
824 
825 	span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
826 			 INT64CONST(1000000) * day) * INT64CONST(86400)) +
827 		interval->time;
828 	span /= USECS_PER_SEC;
829 
830 	if (span < INT_MIN || span > INT_MAX)
831 		time = INVALID_RELTIME;
832 	else
833 		time = span;
834 
835 	PG_RETURN_RELATIVETIME(time);
836 }
837 
838 
839 Datum
reltime_interval(PG_FUNCTION_ARGS)840 reltime_interval(PG_FUNCTION_ARGS)
841 {
842 	RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
843 	Interval   *result;
844 	int			year,
845 				month,
846 				day;
847 
848 	result = (Interval *) palloc(sizeof(Interval));
849 
850 	switch (reltime)
851 	{
852 		case INVALID_RELTIME:
853 			ereport(ERROR,
854 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
855 					 errmsg("cannot convert reltime \"invalid\" to interval")));
856 			result->time = 0;
857 			result->day = 0;
858 			result->month = 0;
859 			break;
860 
861 		default:
862 			year = reltime / SECS_PER_YEAR;
863 			reltime -= year * SECS_PER_YEAR;
864 			month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY);
865 			reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY);
866 			day = reltime / SECS_PER_DAY;
867 			reltime -= day * SECS_PER_DAY;
868 
869 			result->time = (reltime * USECS_PER_SEC);
870 			result->month = MONTHS_PER_YEAR * year + month;
871 			result->day = day;
872 			break;
873 	}
874 
875 	PG_RETURN_INTERVAL_P(result);
876 }
877 
878 
879 /*
880  *		mktinterval		- creates a time interval with endpoints t1 and t2
881  */
882 Datum
mktinterval(PG_FUNCTION_ARGS)883 mktinterval(PG_FUNCTION_ARGS)
884 {
885 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
886 	AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
887 	AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
888 	AbsoluteTime tend = ABSTIMEMAX(t1, t2);
889 	TimeInterval tinterval;
890 
891 	tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
892 
893 	if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
894 		tinterval->status = T_INTERVAL_INVAL;
895 
896 	else
897 	{
898 		tinterval->status = T_INTERVAL_VALID;
899 		tinterval->data[0] = tstart;
900 		tinterval->data[1] = tend;
901 	}
902 
903 	PG_RETURN_TIMEINTERVAL(tinterval);
904 }
905 
906 /*
907  *		timepl, timemi and abstimemi use the formula
908  *				abstime + reltime = abstime
909  *		so		abstime - reltime = abstime
910  *		and		abstime - abstime = reltime
911  */
912 
913 /*
914  *		timepl			- returns the value of (abstime t1 + reltime t2)
915  */
916 Datum
timepl(PG_FUNCTION_ARGS)917 timepl(PG_FUNCTION_ARGS)
918 {
919 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
920 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
921 
922 	if (AbsoluteTimeIsReal(t1) &&
923 		RelativeTimeIsValid(t2) &&
924 		((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
925 		 (t2 <= 0 && t1 > NOSTART_ABSTIME - t2)))	/* prevent overflow */
926 		PG_RETURN_ABSOLUTETIME(t1 + t2);
927 
928 	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
929 }
930 
931 
932 /*
933  *		timemi			- returns the value of (abstime t1 - reltime t2)
934  */
935 Datum
timemi(PG_FUNCTION_ARGS)936 timemi(PG_FUNCTION_ARGS)
937 {
938 	AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
939 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
940 
941 	if (AbsoluteTimeIsReal(t1) &&
942 		RelativeTimeIsValid(t2) &&
943 		((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
944 		 (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
945 		PG_RETURN_ABSOLUTETIME(t1 - t2);
946 
947 	PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
948 }
949 
950 
951 /*
952  *		intinterval		- returns true iff absolute date is in the tinterval
953  */
954 Datum
intinterval(PG_FUNCTION_ARGS)955 intinterval(PG_FUNCTION_ARGS)
956 {
957 	AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
958 	TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1);
959 
960 	if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
961 	{
962 		if (DatumGetBool(DirectFunctionCall2(abstimege,
963 											 AbsoluteTimeGetDatum(t),
964 											 AbsoluteTimeGetDatum(tinterval->data[0]))) &&
965 			DatumGetBool(DirectFunctionCall2(abstimele,
966 											 AbsoluteTimeGetDatum(t),
967 											 AbsoluteTimeGetDatum(tinterval->data[1]))))
968 			PG_RETURN_BOOL(true);
969 	}
970 	PG_RETURN_BOOL(false);
971 }
972 
973 /*
974  *		tintervalrel		- returns  relative time corresponding to tinterval
975  */
976 Datum
tintervalrel(PG_FUNCTION_ARGS)977 tintervalrel(PG_FUNCTION_ARGS)
978 {
979 	TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
980 	AbsoluteTime t1 = tinterval->data[0];
981 	AbsoluteTime t2 = tinterval->data[1];
982 
983 	if (tinterval->status != T_INTERVAL_VALID)
984 		PG_RETURN_RELATIVETIME(INVALID_RELTIME);
985 
986 	if (AbsoluteTimeIsReal(t1) &&
987 		AbsoluteTimeIsReal(t2))
988 		PG_RETURN_RELATIVETIME(t2 - t1);
989 
990 	PG_RETURN_RELATIVETIME(INVALID_RELTIME);
991 }
992 
993 
994 /*
995  *		timenow			- returns  time "now", internal format
996  *
997  *		Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
998  */
999 Datum
timenow(PG_FUNCTION_ARGS)1000 timenow(PG_FUNCTION_ARGS)
1001 {
1002 	PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
1003 }
1004 
1005 /*
1006  * reltime comparison routines
1007  */
1008 static int
reltime_cmp_internal(RelativeTime a,RelativeTime b)1009 reltime_cmp_internal(RelativeTime a, RelativeTime b)
1010 {
1011 	/*
1012 	 * We consider all INVALIDs to be equal and larger than any non-INVALID.
1013 	 * This is somewhat arbitrary; the important thing is to have a consistent
1014 	 * sort order.
1015 	 */
1016 	if (a == INVALID_RELTIME)
1017 	{
1018 		if (b == INVALID_RELTIME)
1019 			return 0;			/* INVALID = INVALID */
1020 		else
1021 			return 1;			/* INVALID > non-INVALID */
1022 	}
1023 
1024 	if (b == INVALID_RELTIME)
1025 		return -1;				/* non-INVALID < INVALID */
1026 
1027 	if (a > b)
1028 		return 1;
1029 	else if (a == b)
1030 		return 0;
1031 	else
1032 		return -1;
1033 }
1034 
1035 Datum
reltimeeq(PG_FUNCTION_ARGS)1036 reltimeeq(PG_FUNCTION_ARGS)
1037 {
1038 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1039 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1040 
1041 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1042 }
1043 
1044 Datum
reltimene(PG_FUNCTION_ARGS)1045 reltimene(PG_FUNCTION_ARGS)
1046 {
1047 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1048 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1049 
1050 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1051 }
1052 
1053 Datum
reltimelt(PG_FUNCTION_ARGS)1054 reltimelt(PG_FUNCTION_ARGS)
1055 {
1056 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1057 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1058 
1059 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1060 }
1061 
1062 Datum
reltimegt(PG_FUNCTION_ARGS)1063 reltimegt(PG_FUNCTION_ARGS)
1064 {
1065 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1066 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1067 
1068 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1069 }
1070 
1071 Datum
reltimele(PG_FUNCTION_ARGS)1072 reltimele(PG_FUNCTION_ARGS)
1073 {
1074 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1075 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1076 
1077 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1078 }
1079 
1080 Datum
reltimege(PG_FUNCTION_ARGS)1081 reltimege(PG_FUNCTION_ARGS)
1082 {
1083 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1084 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1085 
1086 	PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
1087 }
1088 
1089 Datum
btreltimecmp(PG_FUNCTION_ARGS)1090 btreltimecmp(PG_FUNCTION_ARGS)
1091 {
1092 	RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1093 	RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1094 
1095 	PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1096 }
1097 
1098 
1099 /*
1100  *		tintervalsame	- returns true iff tinterval i1 is same as tinterval i2
1101  *		Check begin and end time.
1102  */
1103 Datum
tintervalsame(PG_FUNCTION_ARGS)1104 tintervalsame(PG_FUNCTION_ARGS)
1105 {
1106 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1107 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1108 
1109 	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1110 		PG_RETURN_BOOL(false);
1111 
1112 	if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1113 										 AbsoluteTimeGetDatum(i1->data[0]),
1114 										 AbsoluteTimeGetDatum(i2->data[0]))) &&
1115 		DatumGetBool(DirectFunctionCall2(abstimeeq,
1116 										 AbsoluteTimeGetDatum(i1->data[1]),
1117 										 AbsoluteTimeGetDatum(i2->data[1]))))
1118 		PG_RETURN_BOOL(true);
1119 	PG_RETURN_BOOL(false);
1120 }
1121 
1122 /*
1123  * tinterval comparison routines
1124  *
1125  * Note: comparison is based only on the lengths of the tintervals, not on
1126  * endpoint values (as long as they're not INVALID).  This is pretty bogus,
1127  * but since it's only a legacy datatype, we're not going to change it.
1128  *
1129  * Some other bogus things that won't be changed for compatibility reasons:
1130  * 1. The interval length computations overflow at 2^31 seconds, causing
1131  * intervals longer than that to sort oddly compared to those shorter.
1132  * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
1133  * just ordinary integers.  Since this code doesn't handle them specially,
1134  * it's possible for [a b] to be considered longer than [c infinity] for
1135  * finite abstimes a, b, c.  In combination with the previous point, the
1136  * interval [-infinity infinity] is treated as being shorter than many finite
1137  * intervals :-(
1138  *
1139  * If tinterval is ever reimplemented atop timestamp, it'd be good to give
1140  * some consideration to avoiding these problems.
1141  */
1142 static int
tinterval_cmp_internal(TimeInterval a,TimeInterval b)1143 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1144 {
1145 	bool		a_invalid;
1146 	bool		b_invalid;
1147 	AbsoluteTime a_len;
1148 	AbsoluteTime b_len;
1149 
1150 	/*
1151 	 * We consider all INVALIDs to be equal and larger than any non-INVALID.
1152 	 * This is somewhat arbitrary; the important thing is to have a consistent
1153 	 * sort order.
1154 	 */
1155 	a_invalid = a->status == T_INTERVAL_INVAL ||
1156 		a->data[0] == INVALID_ABSTIME ||
1157 		a->data[1] == INVALID_ABSTIME;
1158 	b_invalid = b->status == T_INTERVAL_INVAL ||
1159 		b->data[0] == INVALID_ABSTIME ||
1160 		b->data[1] == INVALID_ABSTIME;
1161 
1162 	if (a_invalid)
1163 	{
1164 		if (b_invalid)
1165 			return 0;			/* INVALID = INVALID */
1166 		else
1167 			return 1;			/* INVALID > non-INVALID */
1168 	}
1169 
1170 	if (b_invalid)
1171 		return -1;				/* non-INVALID < INVALID */
1172 
1173 	a_len = a->data[1] - a->data[0];
1174 	b_len = b->data[1] - b->data[0];
1175 
1176 	if (a_len > b_len)
1177 		return 1;
1178 	else if (a_len == b_len)
1179 		return 0;
1180 	else
1181 		return -1;
1182 }
1183 
1184 Datum
tintervaleq(PG_FUNCTION_ARGS)1185 tintervaleq(PG_FUNCTION_ARGS)
1186 {
1187 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1188 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1189 
1190 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
1191 }
1192 
1193 Datum
tintervalne(PG_FUNCTION_ARGS)1194 tintervalne(PG_FUNCTION_ARGS)
1195 {
1196 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1197 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1198 
1199 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1200 }
1201 
1202 Datum
tintervallt(PG_FUNCTION_ARGS)1203 tintervallt(PG_FUNCTION_ARGS)
1204 {
1205 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1206 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1207 
1208 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1209 }
1210 
1211 Datum
tintervalle(PG_FUNCTION_ARGS)1212 tintervalle(PG_FUNCTION_ARGS)
1213 {
1214 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1215 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1216 
1217 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1218 }
1219 
1220 Datum
tintervalgt(PG_FUNCTION_ARGS)1221 tintervalgt(PG_FUNCTION_ARGS)
1222 {
1223 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1224 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1225 
1226 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1227 }
1228 
1229 Datum
tintervalge(PG_FUNCTION_ARGS)1230 tintervalge(PG_FUNCTION_ARGS)
1231 {
1232 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1233 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1234 
1235 	PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
1236 }
1237 
1238 Datum
bttintervalcmp(PG_FUNCTION_ARGS)1239 bttintervalcmp(PG_FUNCTION_ARGS)
1240 {
1241 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1242 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1243 
1244 	PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1245 }
1246 
1247 
1248 /*
1249  *		tintervalleneq	- returns true iff length of tinterval i is equal to
1250  *								reltime t
1251  *		tintervallenne	- returns true iff length of tinterval i is not equal
1252  *								to reltime t
1253  *		tintervallenlt	- returns true iff length of tinterval i is less than
1254  *								reltime t
1255  *		tintervallengt	- returns true iff length of tinterval i is greater
1256  *								than reltime t
1257  *		tintervallenle	- returns true iff length of tinterval i is less or
1258  *								equal than reltime t
1259  *		tintervallenge	- returns true iff length of tinterval i is greater or
1260  *								equal than reltime t
1261  */
1262 Datum
tintervalleneq(PG_FUNCTION_ARGS)1263 tintervalleneq(PG_FUNCTION_ARGS)
1264 {
1265 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1266 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1267 	RelativeTime rt;
1268 
1269 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1270 		PG_RETURN_BOOL(false);
1271 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1272 												  TimeIntervalGetDatum(i)));
1273 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1274 }
1275 
1276 Datum
tintervallenne(PG_FUNCTION_ARGS)1277 tintervallenne(PG_FUNCTION_ARGS)
1278 {
1279 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1280 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1281 	RelativeTime rt;
1282 
1283 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1284 		PG_RETURN_BOOL(false);
1285 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1286 												  TimeIntervalGetDatum(i)));
1287 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1288 }
1289 
1290 Datum
tintervallenlt(PG_FUNCTION_ARGS)1291 tintervallenlt(PG_FUNCTION_ARGS)
1292 {
1293 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1294 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1295 	RelativeTime rt;
1296 
1297 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1298 		PG_RETURN_BOOL(false);
1299 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1300 												  TimeIntervalGetDatum(i)));
1301 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1302 }
1303 
1304 Datum
tintervallengt(PG_FUNCTION_ARGS)1305 tintervallengt(PG_FUNCTION_ARGS)
1306 {
1307 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1308 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1309 	RelativeTime rt;
1310 
1311 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1312 		PG_RETURN_BOOL(false);
1313 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1314 												  TimeIntervalGetDatum(i)));
1315 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1316 }
1317 
1318 Datum
tintervallenle(PG_FUNCTION_ARGS)1319 tintervallenle(PG_FUNCTION_ARGS)
1320 {
1321 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1322 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1323 	RelativeTime rt;
1324 
1325 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1326 		PG_RETURN_BOOL(false);
1327 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1328 												  TimeIntervalGetDatum(i)));
1329 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1330 }
1331 
1332 Datum
tintervallenge(PG_FUNCTION_ARGS)1333 tintervallenge(PG_FUNCTION_ARGS)
1334 {
1335 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1336 	RelativeTime t = PG_GETARG_RELATIVETIME(1);
1337 	RelativeTime rt;
1338 
1339 	if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1340 		PG_RETURN_BOOL(false);
1341 	rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1342 												  TimeIntervalGetDatum(i)));
1343 	PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1344 }
1345 
1346 /*
1347  *		tintervalct		- returns true iff tinterval i1 contains tinterval i2
1348  */
1349 Datum
tintervalct(PG_FUNCTION_ARGS)1350 tintervalct(PG_FUNCTION_ARGS)
1351 {
1352 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1353 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1354 
1355 	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1356 		PG_RETURN_BOOL(false);
1357 	if (DatumGetBool(DirectFunctionCall2(abstimele,
1358 										 AbsoluteTimeGetDatum(i1->data[0]),
1359 										 AbsoluteTimeGetDatum(i2->data[0]))) &&
1360 		DatumGetBool(DirectFunctionCall2(abstimege,
1361 										 AbsoluteTimeGetDatum(i1->data[1]),
1362 										 AbsoluteTimeGetDatum(i2->data[1]))))
1363 		PG_RETURN_BOOL(true);
1364 	PG_RETURN_BOOL(false);
1365 }
1366 
1367 /*
1368  *		tintervalov		- returns true iff tinterval i1 (partially) overlaps i2
1369  */
1370 Datum
tintervalov(PG_FUNCTION_ARGS)1371 tintervalov(PG_FUNCTION_ARGS)
1372 {
1373 	TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1374 	TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1375 
1376 	if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1377 		PG_RETURN_BOOL(false);
1378 	if (DatumGetBool(DirectFunctionCall2(abstimelt,
1379 										 AbsoluteTimeGetDatum(i1->data[1]),
1380 										 AbsoluteTimeGetDatum(i2->data[0]))) ||
1381 		DatumGetBool(DirectFunctionCall2(abstimegt,
1382 										 AbsoluteTimeGetDatum(i1->data[0]),
1383 										 AbsoluteTimeGetDatum(i2->data[1]))))
1384 		PG_RETURN_BOOL(false);
1385 	PG_RETURN_BOOL(true);
1386 }
1387 
1388 /*
1389  *		tintervalstart	- returns  the start of tinterval i
1390  */
1391 Datum
tintervalstart(PG_FUNCTION_ARGS)1392 tintervalstart(PG_FUNCTION_ARGS)
1393 {
1394 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1395 
1396 	if (i->status == T_INTERVAL_INVAL)
1397 		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1398 	PG_RETURN_ABSOLUTETIME(i->data[0]);
1399 }
1400 
1401 /*
1402  *		tintervalend		- returns  the end of tinterval i
1403  */
1404 Datum
tintervalend(PG_FUNCTION_ARGS)1405 tintervalend(PG_FUNCTION_ARGS)
1406 {
1407 	TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1408 
1409 	if (i->status == T_INTERVAL_INVAL)
1410 		PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1411 	PG_RETURN_ABSOLUTETIME(i->data[1]);
1412 }
1413 
1414 
1415 /*****************************************************************************
1416  *	 PRIVATE ROUTINES														 *
1417  *****************************************************************************/
1418 
1419 /*
1420  *		parsetinterval -- parse a tinterval string
1421  *
1422  *		output parameters:
1423  *				i_start, i_end: tinterval margins
1424  *
1425  *		Time interval:
1426  *		`[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1427  *
1428  *		OR	`Undefined Range'	(see also INVALID_INTERVAL_STR)
1429  *
1430  *		where <AbsTime> satisfies the syntax of absolute time.
1431  *
1432  *		e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
1433  */
1434 static void
parsetinterval(char * i_string,AbsoluteTime * i_start,AbsoluteTime * i_end)1435 parsetinterval(char *i_string,
1436 			   AbsoluteTime *i_start,
1437 			   AbsoluteTime *i_end)
1438 {
1439 	char	   *p,
1440 			   *p1;
1441 	char		c;
1442 
1443 	p = i_string;
1444 	/* skip leading blanks up to '[' */
1445 	while ((c = *p) != '\0')
1446 	{
1447 		if (IsSpace(c))
1448 			p++;
1449 		else if (c != '[')
1450 			goto bogus;			/* syntax error */
1451 		else
1452 			break;
1453 	}
1454 	if (c == '\0')
1455 		goto bogus;				/* syntax error */
1456 	p++;
1457 	/* skip leading blanks up to '"' */
1458 	while ((c = *p) != '\0')
1459 	{
1460 		if (IsSpace(c))
1461 			p++;
1462 		else if (c != '"')
1463 			goto bogus;			/* syntax error */
1464 		else
1465 			break;
1466 	}
1467 	if (c == '\0')
1468 		goto bogus;				/* syntax error */
1469 	p++;
1470 	if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1471 		goto bogus;				/* undefined range, handled like a syntax err. */
1472 	/* search for the end of the first date and change it to a \0 */
1473 	p1 = p;
1474 	while ((c = *p1) != '\0')
1475 	{
1476 		if (c == '"')
1477 			break;
1478 		p1++;
1479 	}
1480 	if (c == '\0')
1481 		goto bogus;				/* syntax error */
1482 	*p1 = '\0';
1483 	/* get the first date */
1484 	*i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1485 														CStringGetDatum(p)));
1486 	/* undo change to \0 */
1487 	*p1 = c;
1488 	p = ++p1;
1489 	/* skip blanks up to '"', beginning of second date */
1490 	while ((c = *p) != '\0')
1491 	{
1492 		if (IsSpace(c))
1493 			p++;
1494 		else if (c != '"')
1495 			goto bogus;			/* syntax error */
1496 		else
1497 			break;
1498 	}
1499 	if (c == '\0')
1500 		goto bogus;				/* syntax error */
1501 	p++;
1502 	/* search for the end of the second date and change it to a \0 */
1503 	p1 = p;
1504 	while ((c = *p1) != '\0')
1505 	{
1506 		if (c == '"')
1507 			break;
1508 		p1++;
1509 	}
1510 	if (c == '\0')
1511 		goto bogus;				/* syntax error */
1512 	*p1 = '\0';
1513 	/* get the second date */
1514 	*i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1515 													  CStringGetDatum(p)));
1516 	/* undo change to \0 */
1517 	*p1 = c;
1518 	p = ++p1;
1519 	/* skip blanks up to ']' */
1520 	while ((c = *p) != '\0')
1521 	{
1522 		if (IsSpace(c))
1523 			p++;
1524 		else if (c != ']')
1525 			goto bogus;			/* syntax error */
1526 		else
1527 			break;
1528 	}
1529 	if (c == '\0')
1530 		goto bogus;				/* syntax error */
1531 	p++;
1532 	c = *p;
1533 	if (c != '\0')
1534 		goto bogus;				/* syntax error */
1535 
1536 	/* it seems to be a valid tinterval */
1537 	return;
1538 
1539 bogus:
1540 	ereport(ERROR,
1541 			(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1542 			 errmsg("invalid input syntax for type %s: \"%s\"",
1543 					"tinterval", i_string)));
1544 	*i_start = *i_end = INVALID_ABSTIME;	/* keep compiler quiet */
1545 }
1546 
1547 
1548 /*****************************************************************************
1549  *
1550  *****************************************************************************/
1551 
1552 /*
1553  * timeofday -
1554  *	   returns the current time as a text. similar to timenow() but returns
1555  *	   seconds with more precision (up to microsecs). (I need this to compare
1556  *	   the Wisconsin benchmark with Illustra whose TimeNow() shows current
1557  *	   time with precision up to microsecs.)			  - ay 3/95
1558  */
1559 Datum
timeofday(PG_FUNCTION_ARGS)1560 timeofday(PG_FUNCTION_ARGS)
1561 {
1562 	struct timeval tp;
1563 	char		templ[128];
1564 	char		buf[128];
1565 	pg_time_t	tt;
1566 
1567 	gettimeofday(&tp, NULL);
1568 	tt = (pg_time_t) tp.tv_sec;
1569 	pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1570 				pg_localtime(&tt, session_timezone));
1571 	snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1572 
1573 	PG_RETURN_TEXT_P(cstring_to_text(buf));
1574 }
1575