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