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