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