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