]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/nabstime.c
Portability fix from Ryan Kirkpatrick's Alpha patches. I believe this
[postgresql] / src / backend / utils / adt / nabstime.c
1 /*-------------------------------------------------------------------------
2  * nabstime.c
3  *        Utilities for the built-in type "AbsoluteTime".
4  *        Functions for the built-in type "RelativeTime".
5  *        Functions for the built-in type "TimeInterval".
6  *
7  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.77 2000/12/09 20:40:57 tgl Exp $
13  *
14  * NOTES
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include <ctype.h>
21 #include <time.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <float.h>
25 #include <limits.h>
26
27 #if !(defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE))
28 #include <sys/timeb.h>
29 #endif
30
31 #include "access/xact.h"
32 #include "miscadmin.h"
33 #include "utils/builtins.h"
34
35
36 #define MIN_DAYNUM -24856               /* December 13, 1901 */
37 #define MAX_DAYNUM 24854                /* January 18, 2038 */
38
39 #define INVALID_RELTIME_STR             "Undefined RelTime"
40 #define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
41 #define RELTIME_LABEL                   '@'
42 #define RELTIME_PAST                    "ago"
43 #define DIRMAXLEN                               (sizeof(RELTIME_PAST)-1)
44
45 /*
46  * Unix epoch is Jan  1 00:00:00 1970.
47  * Postgres knows about times sixty-eight years on either side of that
48  * for these 4-byte types.
49  *
50  * "tinterval" is two 4-byte fields.
51  * Definitions for parsing tinterval.
52  */
53
54 #define IsSpace(C)                              ((C) == ' ')
55
56 #define T_INTERVAL_INVAL   0    /* data represents no valid interval */
57 #define T_INTERVAL_VALID   1    /* data represents a valid interval */
58 /*
59  * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
60  * 0            1                 2                     3                 4                     5                 6
61  * 1234567890123456789012345678901234567890123456789012345678901234
62  *
63  * we allocate some extra -- timezones are usually 3 characters but
64  * this is not in the POSIX standard...
65  */
66 #define T_INTERVAL_LEN                                  80
67 #define INVALID_INTERVAL_STR                    "Undefined Range"
68 #define INVALID_INTERVAL_STR_LEN                (sizeof(INVALID_INTERVAL_STR)-1)
69
70 #define ABSTIMEMIN(t1, t2) \
71         (DatumGetBool(DirectFunctionCall2(abstimele, \
72                                   AbsoluteTimeGetDatum(t1), \
73                                   AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
74 #define ABSTIMEMAX(t1, t2) \
75         (DatumGetBool(DirectFunctionCall2(abstimelt, \
76                                   AbsoluteTimeGetDatum(t1), \
77                                   AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
78
79 #ifdef NOT_USED
80 static char *unit_tab[] = {
81         "second", "seconds", "minute", "minutes",
82         "hour", "hours", "day", "days", "week", "weeks",
83 "month", "months", "year", "years"};
84
85 #define UNITMAXLEN 7                    /* max length of a unit name */
86 #define NUNITS 14                               /* number of different units */
87
88 /* table of seconds per unit (month = 30 days, year = 365 days)  */
89 static int      sec_tab[] = {
90         1, 1, 60, 60,
91         3600, 3600, 86400, 86400, 604800, 604800,
92 2592000, 2592000, 31536000, 31536000};
93
94 #endif
95
96 /*
97  * Function prototypes -- internal to this file only
98  */
99
100 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
101 static void reltime2tm(RelativeTime time, struct tm * tm);
102
103 #ifdef NOT_USED
104 static int      correct_unit(char *unit, int *unptr);
105 static int      correct_dir(char *direction, int *signptr);
106
107 #endif
108
109 static int istinterval(char *i_string,
110                         AbsoluteTime *i_start,
111                         AbsoluteTime *i_end);
112
113
114 /* GetCurrentAbsoluteTime()
115  * Get the current system time. Set timezone parameters if not specified elsewhere.
116  * Define HasTZSet to allow clients to specify the default timezone.
117  *
118  * Returns the number of seconds since epoch (January 1 1970 GMT)
119  */
120 AbsoluteTime
121 GetCurrentAbsoluteTime(void)
122 {
123         time_t          now;
124
125 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
126         struct tm  *tm;
127
128         now = time(NULL);
129 #else
130         struct timeb tb;                        /* the old V7-ism */
131
132         ftime(&tb);
133         now = tb.time;
134 #endif
135
136         if (!HasCTZSet)
137         {
138 #if defined(HAVE_TM_ZONE)
139                 tm = localtime(&now);
140
141                 CTimeZone = -tm->tm_gmtoff;             /* tm_gmtoff is Sun/DEC-ism */
142                 CDayLight = (tm->tm_isdst > 0);
143
144 #ifdef NOT_USED
145
146                 /*
147                  * XXX is there a better way to get local timezone string w/o
148                  * tzname? - tgl 97/03/18
149                  */
150                 strftime(CTZName, MAXTZLEN, "%Z", tm);
151 #endif
152
153                 /*
154                  * XXX FreeBSD man pages indicate that this should work - thomas
155                  * 1998-12-12
156                  */
157                 strcpy(CTZName, tm->tm_zone);
158
159 #elif defined(HAVE_INT_TIMEZONE)
160                 tm = localtime(&now);
161
162                 CDayLight = tm->tm_isdst;
163                 CTimeZone =
164 # ifdef __CYGWIN__
165                         (tm->tm_isdst ? (_timezone - 3600) : _timezone);
166 # else
167                         (tm->tm_isdst ? (timezone - 3600) : timezone);
168 # endif
169                 strcpy(CTZName, tzname[tm->tm_isdst]);
170 #else /* neither HAVE_TM_ZONE nor HAVE_INT_TIMEZONE */
171                 CTimeZone = tb.timezone * 60;
172                 CDayLight = (tb.dstflag != 0);
173
174                 /*
175                  * XXX does this work to get the local timezone string in V7? -
176                  * tgl 97/03/18
177                  */
178                 strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
179 #endif
180         };
181
182         return (AbsoluteTime) now;
183 }       /* GetCurrentAbsoluteTime() */
184
185
186 void
187 GetCurrentTime(struct tm * tm)
188 {
189         int                     tz;
190
191         abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
192
193         return;
194 }       /* GetCurrentTime() */
195
196
197 void
198 abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char *tzn)
199 {
200         time_t time = (time_t) _time;
201 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
202         struct tm  *tx;
203
204 #else
205         struct timeb tb;                        /* the old V7-ism */
206
207         ftime(&tb);
208 #endif
209
210
211 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
212         if (tzp != NULL)
213                 tx = localtime((time_t *) &time);
214         else
215         {
216                 tx = gmtime((time_t *) &time);
217         };
218
219         tm->tm_year = tx->tm_year + 1900;
220         tm->tm_mon = tx->tm_mon + 1;
221         tm->tm_mday = tx->tm_mday;
222         tm->tm_hour = tx->tm_hour;
223         tm->tm_min = tx->tm_min;
224         tm->tm_sec = tx->tm_sec;
225         tm->tm_isdst = tx->tm_isdst;
226
227 # if defined(HAVE_TM_ZONE)
228         tm->tm_gmtoff = tx->tm_gmtoff;
229         tm->tm_zone = tx->tm_zone;
230
231         if (tzp != NULL)
232                 *tzp = -tm->tm_gmtoff;  /* tm_gmtoff is Sun/DEC-ism */
233         /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
234         if (tzn != NULL)
235         {
236
237                 /*
238                  * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
239                  * contains an error message, which doesn't fit in the buffer
240                  */
241                 StrNCpy(tzn, tm->tm_zone, MAXTZLEN+1);
242                 if (strlen(tm->tm_zone) > MAXTZLEN)
243                         elog(NOTICE, "Invalid timezone \'%s\'", tm->tm_zone);
244         }
245 # elif defined(HAVE_INT_TIMEZONE)
246         if (tzp != NULL)
247 #  ifdef __CYGWIN__
248                 *tzp = (tm->tm_isdst ? (_timezone - 3600) : _timezone);
249 #  else
250                 *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
251 #  endif
252         if (tzn != NULL)
253         {
254
255                 /*
256                  * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
257                  * contains an error message, which doesn't fit in the buffer
258                  */
259                 StrNCpy(tzn, tzname[tm->tm_isdst], MAXTZLEN+1);
260                 if (strlen(tzname[tm->tm_isdst]) > MAXTZLEN)
261                         elog(NOTICE, "Invalid timezone \'%s\'", tzname[tm->tm_isdst]);
262         }
263 # endif
264 #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
265         if (tzp != NULL)
266                 *tzp = tb.timezone * 60;
267
268         /*
269          * XXX does this work to get the local timezone string in V7? - tgl
270          * 97/03/18
271          */
272         if (tzn != NULL)
273         {
274                 strftime(tzn, MAXTZLEN, "%Z", localtime(&now));
275                 tzn[MAXTZLEN] = '\0';   /* let's just be sure it's null-terminated */
276         }
277 #endif
278
279         return;
280 }       /* abstime2tm() */
281
282
283 /* tm2abstime()
284  * Convert a tm structure to abstime.
285  * Note that tm has full year (not 1900-based) and 1-based month.
286  */
287 static AbsoluteTime
288 tm2abstime(struct tm * tm, int tz)
289 {
290         int                     day;
291         AbsoluteTime sec;
292
293         /* validate, before going out of range on some members */
294         if (tm->tm_year < 1901 || tm->tm_year > 2038
295                 || tm->tm_mon < 1 || tm->tm_mon > 12
296                 || tm->tm_mday < 1 || tm->tm_mday > 31
297                 || tm->tm_hour < 0 || tm->tm_hour >= 24
298                 || tm->tm_min < 0 || tm->tm_min > 59
299                 || tm->tm_sec < 0 || tm->tm_sec > 59)
300                 return INVALID_ABSTIME;
301
302         day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
303
304         /* check for time out of range */
305         if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
306                 return INVALID_ABSTIME;
307
308         /* convert to seconds */
309         sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
310
311         /* check for overflow */
312         if ((day == MAX_DAYNUM && sec < 0) ||
313                 (day == MIN_DAYNUM && sec > 0))
314                 return INVALID_ABSTIME;
315
316         /* check for reserved values (e.g. "current" on edge of usual range */
317         if (!AbsoluteTimeIsReal(sec))
318                 return INVALID_ABSTIME;
319
320         return sec;
321 }       /* tm2abstime() */
322
323
324 /* nabstimein()
325  * Decode date/time string and return abstime.
326  */
327 Datum
328 nabstimein(PG_FUNCTION_ARGS)
329 {
330         char       *str = PG_GETARG_CSTRING(0);
331         AbsoluteTime result;
332         double          fsec;
333         int                     tz = 0;
334         struct tm       date,
335                            *tm = &date;
336         char       *field[MAXDATEFIELDS];
337         char            lowstr[MAXDATELEN + 1];
338         int                     dtype;
339         int                     nf,
340                                 ftype[MAXDATEFIELDS];
341
342         if (strlen(str) > MAXDATELEN)
343                 elog(ERROR, "Bad (length) abstime external representation '%s'", str);
344
345         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
346           || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
347                 elog(ERROR, "Bad abstime external representation '%s'", str);
348
349         switch (dtype)
350         {
351                 case DTK_DATE:
352                         result = tm2abstime(tm, tz);
353                         break;
354
355                 case DTK_EPOCH:
356                         result = EPOCH_ABSTIME;
357                         break;
358
359                 case DTK_CURRENT:
360                         result = CURRENT_ABSTIME;
361                         break;
362
363                 case DTK_LATE:
364                         result = NOEND_ABSTIME;
365                         break;
366
367                 case DTK_EARLY:
368                         result = NOSTART_ABSTIME;
369                         break;
370
371                 case DTK_INVALID:
372                         result = INVALID_ABSTIME;
373                         break;
374
375                 default:
376                         elog(ERROR, "Bad abstime (internal coding error) '%s'", str);
377                         result = INVALID_ABSTIME;
378                         break;
379         };
380
381         PG_RETURN_ABSOLUTETIME(result);
382 }
383
384
385 /* nabstimeout()
386  * Given an AbsoluteTime return the English text version of the date
387  */
388 Datum
389 nabstimeout(PG_FUNCTION_ARGS)
390 {
391         AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
392         char       *result;
393         int                     tz;
394         double          fsec = 0;
395         struct tm       tt,
396                            *tm = &tt;
397         char            buf[MAXDATELEN + 1];
398         char            zone[MAXDATELEN + 1],
399                            *tzn = zone;
400
401         switch (time)
402         {
403                 case EPOCH_ABSTIME:
404                         strcpy(buf, EPOCH);
405                         break;
406                 case INVALID_ABSTIME:
407                         strcpy(buf, INVALID);
408                         break;
409                 case CURRENT_ABSTIME:
410                         strcpy(buf, DCURRENT);
411                         break;
412                 case NOEND_ABSTIME:
413                         strcpy(buf, LATE);
414                         break;
415                 case NOSTART_ABSTIME:
416                         strcpy(buf, EARLY);
417                         break;
418                 default:
419                         abstime2tm(time, &tz, tm, tzn);
420                         EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
421                         break;
422         }
423
424         result = pstrdup(buf);
425         PG_RETURN_CSTRING(result);
426 }
427
428
429 /*
430  *      AbsoluteTimeIsBefore -- true iff time1 is before time2.
431  *      AbsoluteTimeIsBefore -- true iff time1 is after time2.
432  */
433 bool
434 AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
435 {
436         Assert(AbsoluteTimeIsValid(time1));
437         Assert(AbsoluteTimeIsValid(time2));
438
439         if (time1 == CURRENT_ABSTIME)
440                 time1 = GetCurrentTransactionStartTime();
441
442         if (time2 == CURRENT_ABSTIME)
443                 time2 = GetCurrentTransactionStartTime();
444
445         return time1 < time2;
446 }
447
448 #ifdef NOT_USED
449 bool
450 AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
451 {
452         Assert(AbsoluteTimeIsValid(time1));
453         Assert(AbsoluteTimeIsValid(time2));
454
455         if (time1 == CURRENT_ABSTIME)
456                 time1 = GetCurrentTransactionStartTime();
457
458         if (time2 == CURRENT_ABSTIME)
459                 time2 = GetCurrentTransactionStartTime();
460
461         return time1 > time2;
462 }
463
464 #endif
465
466 /* abstime_finite()
467  */
468 Datum
469 abstime_finite(PG_FUNCTION_ARGS)
470 {
471         AbsoluteTime    abstime = PG_GETARG_ABSOLUTETIME(0);
472
473         PG_RETURN_BOOL((abstime != INVALID_ABSTIME) &&
474                                    (abstime != NOSTART_ABSTIME) &&
475                                    (abstime != NOEND_ABSTIME));
476 }
477
478
479 /*
480  *              abstimeeq               - returns true iff arguments are equal
481  *              abstimene               - returns true iff arguments are not equal
482  *              abstimelt               - returns true iff t1 less than t2
483  *              abstimegt               - returns true iff t1 greater than t2
484  *              abstimele               - returns true iff t1 less than or equal to t2
485  *              abstimege               - returns true iff t1 greater than or equal to t2
486  */
487 Datum
488 abstimeeq(PG_FUNCTION_ARGS)
489 {
490         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
491         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
492
493         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
494                 PG_RETURN_BOOL(false);
495         if (t1 == CURRENT_ABSTIME)
496                 t1 = GetCurrentTransactionStartTime();
497         if (t2 == CURRENT_ABSTIME)
498                 t2 = GetCurrentTransactionStartTime();
499
500         PG_RETURN_BOOL(t1 == t2);
501 }
502
503 Datum
504 abstimene(PG_FUNCTION_ARGS)
505 {
506         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
507         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
508
509         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
510                 PG_RETURN_BOOL(false);
511         if (t1 == CURRENT_ABSTIME)
512                 t1 = GetCurrentTransactionStartTime();
513         if (t2 == CURRENT_ABSTIME)
514                 t2 = GetCurrentTransactionStartTime();
515
516         PG_RETURN_BOOL(t1 != t2);
517 }
518
519 Datum
520 abstimelt(PG_FUNCTION_ARGS)
521 {
522         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
523         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
524
525         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
526                 PG_RETURN_BOOL(false);
527         if (t1 == CURRENT_ABSTIME)
528                 t1 = GetCurrentTransactionStartTime();
529         if (t2 == CURRENT_ABSTIME)
530                 t2 = GetCurrentTransactionStartTime();
531
532         PG_RETURN_BOOL(t1 < t2);
533 }
534
535 Datum
536 abstimegt(PG_FUNCTION_ARGS)
537 {
538         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
539         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
540
541         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
542                 PG_RETURN_BOOL(false);
543         if (t1 == CURRENT_ABSTIME)
544                 t1 = GetCurrentTransactionStartTime();
545         if (t2 == CURRENT_ABSTIME)
546                 t2 = GetCurrentTransactionStartTime();
547
548         PG_RETURN_BOOL(t1 > t2);
549 }
550
551 Datum
552 abstimele(PG_FUNCTION_ARGS)
553 {
554         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
555         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
556
557         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
558                 PG_RETURN_BOOL(false);
559         if (t1 == CURRENT_ABSTIME)
560                 t1 = GetCurrentTransactionStartTime();
561         if (t2 == CURRENT_ABSTIME)
562                 t2 = GetCurrentTransactionStartTime();
563
564         PG_RETURN_BOOL(t1 <= t2);
565 }
566
567 Datum
568 abstimege(PG_FUNCTION_ARGS)
569 {
570         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
571         AbsoluteTime    t2 = PG_GETARG_ABSOLUTETIME(1);
572
573         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
574                 PG_RETURN_BOOL(false);
575         if (t1 == CURRENT_ABSTIME)
576                 t1 = GetCurrentTransactionStartTime();
577         if (t2 == CURRENT_ABSTIME)
578                 t2 = GetCurrentTransactionStartTime();
579
580         PG_RETURN_BOOL(t1 >= t2);
581 }
582
583
584 /* datetime_abstime()
585  * Convert timestamp to abstime.
586  */
587 Datum
588 timestamp_abstime(PG_FUNCTION_ARGS)
589 {
590         Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
591         AbsoluteTime result;
592         double          fsec;
593         struct tm       tt,
594                            *tm = &tt;
595
596         if (TIMESTAMP_IS_INVALID(timestamp))
597         {
598                 result = INVALID_ABSTIME;
599         }
600         else if (TIMESTAMP_IS_NOBEGIN(timestamp))
601         {
602                 result = NOSTART_ABSTIME;
603         }
604         else if (TIMESTAMP_IS_NOEND(timestamp))
605         {
606                 result = NOEND_ABSTIME;
607         }
608         else
609         {
610                 if (TIMESTAMP_IS_RELATIVE(timestamp))
611                 {
612                         timestamp2tm(SetTimestamp(timestamp), NULL, tm, &fsec, NULL);
613                         result = tm2abstime(tm, 0);
614                 }
615                 else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
616                 {
617                         result = tm2abstime(tm, 0);
618                 }
619                 else
620                 {
621                         result = INVALID_ABSTIME;
622                 }
623         }
624
625         PG_RETURN_ABSOLUTETIME(result);
626 }
627
628 /* abstime_timestamp()
629  * Convert abstime to timestamp.
630  */
631 Datum
632 abstime_timestamp(PG_FUNCTION_ARGS)
633 {
634         AbsoluteTime    abstime = PG_GETARG_ABSOLUTETIME(0);
635         Timestamp       result;
636
637         switch (abstime)
638         {
639                 case INVALID_ABSTIME:
640                         TIMESTAMP_INVALID(result);
641                         break;
642
643                 case NOSTART_ABSTIME:
644                         TIMESTAMP_NOBEGIN(result);
645                         break;
646
647                 case NOEND_ABSTIME:
648                         TIMESTAMP_NOEND(result);
649                         break;
650
651                 case EPOCH_ABSTIME:
652                         TIMESTAMP_EPOCH(result);
653                         break;
654
655                 case CURRENT_ABSTIME:
656                         TIMESTAMP_CURRENT(result);
657                         break;
658
659                 default:
660                         result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
661                         break;
662         };
663
664         PG_RETURN_TIMESTAMP(result);
665 }
666
667
668 /*****************************************************************************
669  *       USER I/O ROUTINES                                                                                                               *
670  *****************************************************************************/
671
672 /*
673  *              reltimein               - converts a reltime string in an internal format
674  */
675 Datum
676 reltimein(PG_FUNCTION_ARGS)
677 {
678         char            *str = PG_GETARG_CSTRING(0);
679         RelativeTime result;
680         struct tm       tt,
681                            *tm = &tt;
682         double          fsec;
683         int                     dtype;
684         char       *field[MAXDATEFIELDS];
685         int                     nf,
686                                 ftype[MAXDATEFIELDS];
687         char            lowstr[MAXDATELEN + 1];
688
689         if (strlen(str) > MAXDATELEN)
690                 elog(ERROR, "Bad (length) reltime external representation '%s'", str);
691
692         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
693                 || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
694                 elog(ERROR, "Bad reltime external representation '%s'", str);
695
696         switch (dtype)
697         {
698                 case DTK_DELTA:
699                         result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
700                         result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60));
701                         PG_RETURN_RELATIVETIME(result);
702
703                 default:
704                         PG_RETURN_RELATIVETIME(INVALID_RELTIME);
705         }
706
707         elog(ERROR, "Bad reltime (internal coding error) '%s'", str);
708         PG_RETURN_RELATIVETIME(INVALID_RELTIME);
709 }
710
711
712 /*
713  *              reltimeout              - converts the internal format to a reltime string
714  */
715 Datum
716 reltimeout(PG_FUNCTION_ARGS)
717 {
718         RelativeTime time = PG_GETARG_RELATIVETIME(0);
719         char       *result;
720         struct tm       tt,
721                            *tm = &tt;
722         char            buf[MAXDATELEN + 1];
723
724         if (time == INVALID_RELTIME)
725         {
726                 strcpy(buf, INVALID_RELTIME_STR);
727         }
728         else
729         {
730                 reltime2tm(time, tm);
731                 EncodeTimeSpan(tm, 0, DateStyle, buf);
732         }
733
734         result = pstrdup(buf);
735         PG_RETURN_CSTRING(result);
736 }
737
738
739 static void
740 reltime2tm(RelativeTime time, struct tm * tm)
741 {
742         TMODULO(time, tm->tm_year, 31536000);
743         TMODULO(time, tm->tm_mon, 2592000);
744         TMODULO(time, tm->tm_mday, 86400);
745         TMODULO(time, tm->tm_hour, 3600);
746         TMODULO(time, tm->tm_min, 60);
747         TMODULO(time, tm->tm_sec, 1);
748
749         return;
750 }       /* reltime2tm() */
751
752 #ifdef NOT_USED
753 int
754 dummyfunc()
755 {
756         char       *timestring;
757         long            quantity;
758         int                     i;
759         int                     unitnr;
760
761         timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR),
762                                                                          UNITMAXLEN) + 1);
763         if (timevalue == INVALID_RELTIME)
764         {
765                 strcpy(timestring, INVALID_RELTIME_STR);
766                 return timestring;
767         }
768
769         if (timevalue == 0)
770                 i = 1;                                  /* unit = 'seconds' */
771         else
772                 for (i = 12; i >= 0; i = i - 2)
773                         if ((timevalue % sec_tab[i]) == 0)
774                                 break;                  /* appropriate unit found */
775         unitnr = i;
776         quantity = (timevalue / sec_tab[unitnr]);
777         if (quantity > 1 || quantity < -1)
778                 unitnr++;                               /* adjust index for PLURAL of unit */
779         if (quantity >= 0)
780                 sprintf(timestring, "%c %lu %s", RELTIME_LABEL,
781                                 quantity, unit_tab[unitnr]);
782         else
783                 sprintf(timestring, "%c %lu %s %s", RELTIME_LABEL,
784                                 (quantity * -1), unit_tab[unitnr], RELTIME_PAST);
785         return timestring;
786 }
787
788 #endif
789
790
791 /*
792  *              tintervalin             - converts an interval string to internal format
793  */
794 Datum
795 tintervalin(PG_FUNCTION_ARGS)
796 {
797         char       *intervalstr = PG_GETARG_CSTRING(0);
798         TimeInterval interval;
799         int                     error;
800         AbsoluteTime i_start,
801                                 i_end,
802                                 t1,
803                                 t2;
804
805         interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
806         error = istinterval(intervalstr, &t1, &t2);
807         if (error == 0)
808                 interval->status = T_INTERVAL_INVAL;
809         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
810                 interval->status = T_INTERVAL_INVAL;    /* undefined  */
811         else
812         {
813                 i_start = ABSTIMEMIN(t1, t2);
814                 i_end = ABSTIMEMAX(t1, t2);
815                 interval->data[0] = i_start;
816                 interval->data[1] = i_end;
817                 interval->status = T_INTERVAL_VALID;
818         }
819         PG_RETURN_TIMEINTERVAL(interval);
820 }
821
822
823 /*
824  *              tintervalout    - converts an internal interval format to a string
825  *
826  */
827 Datum
828 tintervalout(PG_FUNCTION_ARGS)
829 {
830         TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
831         char       *i_str,
832                            *p;
833
834         i_str = (char *) palloc(T_INTERVAL_LEN);        /* ['...' '...'] */
835         strcpy(i_str, "[\"");
836         if (interval->status == T_INTERVAL_INVAL)
837                 strcat(i_str, INVALID_INTERVAL_STR);
838         else
839         {
840                 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
841                                                         AbsoluteTimeGetDatum(interval->data[0])));
842                 strcat(i_str, p);
843                 pfree(p);
844                 strcat(i_str, "\" \"");
845                 p = DatumGetCString(DirectFunctionCall1(nabstimeout,
846                                                         AbsoluteTimeGetDatum(interval->data[1])));
847                 strcat(i_str, p);
848                 pfree(p);
849         }
850         strcat(i_str, "\"]\0");
851         PG_RETURN_CSTRING(i_str);
852 }
853
854
855 /*****************************************************************************
856  *       PUBLIC ROUTINES                                                                                                                 *
857  *****************************************************************************/
858
859 Datum
860 interval_reltime(PG_FUNCTION_ARGS)
861 {
862         Interval   *interval = PG_GETARG_INTERVAL_P(0);
863         RelativeTime time;
864         int                     year,
865                                 month;
866         double          span;
867
868         if (INTERVAL_IS_INVALID(*interval))
869         {
870                 time = INVALID_RELTIME;
871         }
872         else
873         {
874                 if (interval->month == 0)
875                 {
876                         year = 0;
877                         month = 0;
878                 }
879                 else if (abs(interval->month) >= 12)
880                 {
881                         year = (interval->month / 12);
882                         month = (interval->month % 12);
883                 }
884                 else
885                 {
886                         year = 0;
887                         month = interval->month;
888                 }
889
890                 span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time);
891
892                 time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME);
893         }
894
895         PG_RETURN_RELATIVETIME(time);
896 }
897
898
899 Datum
900 reltime_interval(PG_FUNCTION_ARGS)
901 {
902         RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
903         Interval   *result;
904         int                     year,
905                                 month;
906
907         result = (Interval *) palloc(sizeof(Interval));
908
909         switch (reltime)
910         {
911                 case INVALID_RELTIME:
912                         INTERVAL_INVALID(*result);
913                         break;
914
915                 default:
916                         TMODULO(reltime, year, 31536000);
917                         TMODULO(reltime, month, 2592000);
918
919                         result->time = reltime;
920                         result->month = ((12 * year) + month);
921                         break;
922         }
923
924         PG_RETURN_INTERVAL_P(result);
925 }
926
927
928 /*
929  *              mktinterval             - creates a time interval with endpoints t1 and t2
930  */
931 Datum
932 mktinterval(PG_FUNCTION_ARGS)
933 {
934         AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
935         AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
936         AbsoluteTime tstart = ABSTIMEMIN(t1, t2),
937                                 tend = ABSTIMEMAX(t1, t2);
938         TimeInterval interval;
939
940         interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
941         if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
942                 interval->status = T_INTERVAL_INVAL;
943         else
944         {
945                 interval->status = T_INTERVAL_VALID;
946                 interval->data[0] = tstart;
947                 interval->data[1] = tend;
948         }
949
950         PG_RETURN_TIMEINTERVAL(interval);
951 }
952
953 /*
954  *              timepl, timemi and abstimemi use the formula
955  *                              abstime + reltime = abstime
956  *              so              abstime - reltime = abstime
957  *              and             abstime - abstime = reltime
958  */
959
960 /*
961  *              timepl                  - returns the value of (abstime t1 + relime t2)
962  */
963 Datum
964 timepl(PG_FUNCTION_ARGS)
965 {
966         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
967         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
968
969         if (t1 == CURRENT_ABSTIME)
970                 t1 = GetCurrentTransactionStartTime();
971
972         if (AbsoluteTimeIsReal(t1) &&
973                 RelativeTimeIsValid(t2) &&
974                 ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
975                  : (t1 > NOSTART_ABSTIME - t2)))                /* prevent overflow */
976                 PG_RETURN_ABSOLUTETIME(t1 + t2);
977
978         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
979 }
980
981
982 /*
983  *              timemi                  - returns the value of (abstime t1 - reltime t2)
984  */
985 Datum
986 timemi(PG_FUNCTION_ARGS)
987 {
988         AbsoluteTime    t1 = PG_GETARG_ABSOLUTETIME(0);
989         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
990
991         if (t1 == CURRENT_ABSTIME)
992                 t1 = GetCurrentTransactionStartTime();
993
994         if (AbsoluteTimeIsReal(t1) &&
995                 RelativeTimeIsValid(t2) &&
996                 ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
997                  : (t1 < NOEND_ABSTIME + t2)))  /* prevent overflow */
998                 PG_RETURN_ABSOLUTETIME(t1 - t2);
999
1000         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1001 }
1002
1003
1004 /*
1005  *              abstimemi               - returns the value of (abstime t1 - abstime t2)
1006  *
1007  * This is not exported, so it's not been made fmgr-compatible.
1008  */
1009 static RelativeTime
1010 abstimemi(AbsoluteTime t1, AbsoluteTime t2)
1011 {
1012         if (t1 == CURRENT_ABSTIME)
1013                 t1 = GetCurrentTransactionStartTime();
1014         if (t2 == CURRENT_ABSTIME)
1015                 t2 = GetCurrentTransactionStartTime();
1016
1017         if (AbsoluteTimeIsReal(t1) &&
1018                 AbsoluteTimeIsReal(t2))
1019                 return t1 - t2;
1020
1021         return INVALID_RELTIME;
1022 }
1023
1024
1025 /*
1026  *              intinterval             - returns true iff absolute date is in the interval
1027  */
1028 Datum
1029 intinterval(PG_FUNCTION_ARGS)
1030 {
1031         AbsoluteTime    t = PG_GETARG_ABSOLUTETIME(0);
1032         TimeInterval    interval = PG_GETARG_TIMEINTERVAL(1);
1033
1034         if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
1035         {
1036                 if (DatumGetBool(DirectFunctionCall2(abstimege,
1037                                                  AbsoluteTimeGetDatum(t),
1038                                                  AbsoluteTimeGetDatum(interval->data[0]))) &&
1039                         DatumGetBool(DirectFunctionCall2(abstimele,
1040                                                  AbsoluteTimeGetDatum(t),
1041                                                  AbsoluteTimeGetDatum(interval->data[1]))))
1042                         PG_RETURN_BOOL(true);
1043         }
1044         PG_RETURN_BOOL(false);
1045 }
1046
1047 /*
1048  *              tintervalrel            - returns  relative time corresponding to interval
1049  */
1050 Datum
1051 tintervalrel(PG_FUNCTION_ARGS)
1052 {
1053         TimeInterval interval = PG_GETARG_TIMEINTERVAL(0);
1054
1055         if (interval->status != T_INTERVAL_VALID)
1056                 PG_RETURN_RELATIVETIME(INVALID_RELTIME);
1057
1058         PG_RETURN_RELATIVETIME(abstimemi(interval->data[1], interval->data[0]));
1059 }
1060
1061 /*
1062  *              timenow                 - returns  time "now", internal format
1063  *
1064  *              Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
1065  */
1066 Datum
1067 timenow(PG_FUNCTION_ARGS)
1068 {
1069         time_t          sec;
1070
1071         if (time(&sec) < 0)
1072                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1073         PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
1074 }
1075
1076 /*
1077  *              reltimeeq               - returns true iff arguments are equal
1078  *              reltimene               - returns true iff arguments are not equal
1079  *              reltimelt               - returns true iff t1 less than t2
1080  *              reltimegt               - returns true iff t1 greater than t2
1081  *              reltimele               - returns true iff t1 less than or equal to t2
1082  *              reltimege               - returns true iff t1 greater than or equal to t2
1083  */
1084 Datum
1085 reltimeeq(PG_FUNCTION_ARGS)
1086 {
1087         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1088         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1089
1090         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1091                 PG_RETURN_BOOL(false);
1092         PG_RETURN_BOOL(t1 == t2);
1093 }
1094
1095 Datum
1096 reltimene(PG_FUNCTION_ARGS)
1097 {
1098         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1099         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1100
1101         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1102                 PG_RETURN_BOOL(false);
1103         PG_RETURN_BOOL(t1 != t2);
1104 }
1105
1106 Datum
1107 reltimelt(PG_FUNCTION_ARGS)
1108 {
1109         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1110         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1111
1112         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1113                 PG_RETURN_BOOL(false);
1114         PG_RETURN_BOOL(t1 < t2);
1115 }
1116
1117 Datum
1118 reltimegt(PG_FUNCTION_ARGS)
1119 {
1120         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1121         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1122
1123         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1124                 PG_RETURN_BOOL(false);
1125         PG_RETURN_BOOL(t1 > t2);
1126 }
1127
1128 Datum
1129 reltimele(PG_FUNCTION_ARGS)
1130 {
1131         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1132         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1133
1134         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1135                 PG_RETURN_BOOL(false);
1136         PG_RETURN_BOOL(t1 <= t2);
1137 }
1138
1139 Datum
1140 reltimege(PG_FUNCTION_ARGS)
1141 {
1142         RelativeTime    t1 = PG_GETARG_RELATIVETIME(0);
1143         RelativeTime    t2 = PG_GETARG_RELATIVETIME(1);
1144
1145         if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
1146                 PG_RETURN_BOOL(false);
1147         PG_RETURN_BOOL(t1 >= t2);
1148 }
1149
1150
1151 /*
1152  *              tintervalsame   - returns true iff interval i1 is same as interval i2
1153  *              Check begin and end time.
1154  */
1155 Datum
1156 tintervalsame(PG_FUNCTION_ARGS)
1157 {
1158         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1159         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1160
1161         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1162                 PG_RETURN_BOOL(false);
1163
1164         if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1165                                                                                  AbsoluteTimeGetDatum(i1->data[0]),
1166                                                                                  AbsoluteTimeGetDatum(i2->data[0]))) &&
1167                 DatumGetBool(DirectFunctionCall2(abstimeeq,
1168                                                                                  AbsoluteTimeGetDatum(i1->data[1]),
1169                                                                                  AbsoluteTimeGetDatum(i2->data[1]))))
1170                 PG_RETURN_BOOL(true);
1171         PG_RETURN_BOOL(false);
1172 }
1173
1174
1175 /*
1176  *              tintervaleq             - returns true iff interval i1 is equal to interval i2
1177  *              Check length of intervals.
1178  */
1179 Datum
1180 tintervaleq(PG_FUNCTION_ARGS)
1181 {
1182         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1183         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1184         AbsoluteTime t10,
1185                                 t11,
1186                                 t20,
1187                                 t21;
1188
1189         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1190                 PG_RETURN_BOOL(false);
1191
1192         t10 = i1->data[0];
1193         t11 = i1->data[1];
1194         t20 = i2->data[0];
1195         t21 = i2->data[1];
1196
1197         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1198                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1199                 PG_RETURN_BOOL(false);
1200
1201         if (t10 == CURRENT_ABSTIME)
1202                 t10 = GetCurrentTransactionStartTime();
1203         if (t11 == CURRENT_ABSTIME)
1204                 t11 = GetCurrentTransactionStartTime();
1205         if (t20 == CURRENT_ABSTIME)
1206                 t20 = GetCurrentTransactionStartTime();
1207         if (t21 == CURRENT_ABSTIME)
1208                 t21 = GetCurrentTransactionStartTime();
1209
1210         PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
1211 }
1212
1213 Datum
1214 tintervalne(PG_FUNCTION_ARGS)
1215 {
1216         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1217         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1218         AbsoluteTime t10,
1219                                 t11,
1220                                 t20,
1221                                 t21;
1222
1223         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1224                 PG_RETURN_BOOL(false);
1225
1226         t10 = i1->data[0];
1227         t11 = i1->data[1];
1228         t20 = i2->data[0];
1229         t21 = i2->data[1];
1230
1231         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1232                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1233                 PG_RETURN_BOOL(false);
1234
1235         if (t10 == CURRENT_ABSTIME)
1236                 t10 = GetCurrentTransactionStartTime();
1237         if (t11 == CURRENT_ABSTIME)
1238                 t11 = GetCurrentTransactionStartTime();
1239         if (t20 == CURRENT_ABSTIME)
1240                 t20 = GetCurrentTransactionStartTime();
1241         if (t21 == CURRENT_ABSTIME)
1242                 t21 = GetCurrentTransactionStartTime();
1243
1244         PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
1245 }
1246
1247 Datum
1248 tintervallt(PG_FUNCTION_ARGS)
1249 {
1250         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1251         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1252         AbsoluteTime t10,
1253                                 t11,
1254                                 t20,
1255                                 t21;
1256
1257         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1258                 PG_RETURN_BOOL(false);
1259
1260         t10 = i1->data[0];
1261         t11 = i1->data[1];
1262         t20 = i2->data[0];
1263         t21 = i2->data[1];
1264
1265         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1266                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1267                 PG_RETURN_BOOL(false);
1268
1269         if (t10 == CURRENT_ABSTIME)
1270                 t10 = GetCurrentTransactionStartTime();
1271         if (t11 == CURRENT_ABSTIME)
1272                 t11 = GetCurrentTransactionStartTime();
1273         if (t20 == CURRENT_ABSTIME)
1274                 t20 = GetCurrentTransactionStartTime();
1275         if (t21 == CURRENT_ABSTIME)
1276                 t21 = GetCurrentTransactionStartTime();
1277
1278         PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
1279 }
1280
1281 Datum
1282 tintervalle(PG_FUNCTION_ARGS)
1283 {
1284         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1285         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1286         AbsoluteTime t10,
1287                                 t11,
1288                                 t20,
1289                                 t21;
1290
1291         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1292                 PG_RETURN_BOOL(false);
1293
1294         t10 = i1->data[0];
1295         t11 = i1->data[1];
1296         t20 = i2->data[0];
1297         t21 = i2->data[1];
1298
1299         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1300                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1301                 PG_RETURN_BOOL(false);
1302
1303         if (t10 == CURRENT_ABSTIME)
1304                 t10 = GetCurrentTransactionStartTime();
1305         if (t11 == CURRENT_ABSTIME)
1306                 t11 = GetCurrentTransactionStartTime();
1307         if (t20 == CURRENT_ABSTIME)
1308                 t20 = GetCurrentTransactionStartTime();
1309         if (t21 == CURRENT_ABSTIME)
1310                 t21 = GetCurrentTransactionStartTime();
1311
1312         PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
1313 }
1314
1315 Datum
1316 tintervalgt(PG_FUNCTION_ARGS)
1317 {
1318         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1319         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1320         AbsoluteTime t10,
1321                                 t11,
1322                                 t20,
1323                                 t21;
1324
1325         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1326                 PG_RETURN_BOOL(false);
1327
1328         t10 = i1->data[0];
1329         t11 = i1->data[1];
1330         t20 = i2->data[0];
1331         t21 = i2->data[1];
1332
1333         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1334                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1335                 PG_RETURN_BOOL(false);
1336
1337         if (t10 == CURRENT_ABSTIME)
1338                 t10 = GetCurrentTransactionStartTime();
1339         if (t11 == CURRENT_ABSTIME)
1340                 t11 = GetCurrentTransactionStartTime();
1341         if (t20 == CURRENT_ABSTIME)
1342                 t20 = GetCurrentTransactionStartTime();
1343         if (t21 == CURRENT_ABSTIME)
1344                 t21 = GetCurrentTransactionStartTime();
1345
1346         PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
1347 }
1348
1349 Datum
1350 tintervalge(PG_FUNCTION_ARGS)
1351 {
1352         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1353         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1354         AbsoluteTime t10,
1355                                 t11,
1356                                 t20,
1357                                 t21;
1358
1359         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1360                 PG_RETURN_BOOL(false);
1361
1362         t10 = i1->data[0];
1363         t11 = i1->data[1];
1364         t20 = i2->data[0];
1365         t21 = i2->data[1];
1366
1367         if ((t10 == INVALID_ABSTIME) || (t20 == INVALID_ABSTIME)
1368                 || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
1369                 PG_RETURN_BOOL(false);
1370
1371         if (t10 == CURRENT_ABSTIME)
1372                 t10 = GetCurrentTransactionStartTime();
1373         if (t11 == CURRENT_ABSTIME)
1374                 t11 = GetCurrentTransactionStartTime();
1375         if (t20 == CURRENT_ABSTIME)
1376                 t20 = GetCurrentTransactionStartTime();
1377         if (t21 == CURRENT_ABSTIME)
1378                 t21 = GetCurrentTransactionStartTime();
1379
1380         PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
1381 }
1382
1383
1384 /*
1385  *              tintervalleneq  - returns true iff length of interval i is equal to
1386  *                                                              reltime t
1387  *              tintervallenne  - returns true iff length of interval i is not equal
1388  *                                                              to reltime t
1389  *              tintervallenlt  - returns true iff length of interval i is less than
1390  *                                                              reltime t
1391  *              tintervallengt  - returns true iff length of interval i is greater
1392  *                                                              than reltime t
1393  *              tintervallenle  - returns true iff length of interval i is less or
1394  *                                                              equal than reltime t
1395  *              tintervallenge  - returns true iff length of interval i is greater or
1396  *                                                              equal than reltime t
1397  */
1398 Datum
1399 tintervalleneq(PG_FUNCTION_ARGS)
1400 {
1401         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1402         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1403         RelativeTime rt;
1404
1405         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1406                 PG_RETURN_BOOL(false);
1407         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1408                                                                                                   TimeIntervalGetDatum(i)));
1409         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
1410 }
1411
1412 Datum
1413 tintervallenne(PG_FUNCTION_ARGS)
1414 {
1415         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1416         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1417         RelativeTime rt;
1418
1419         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1420                 PG_RETURN_BOOL(false);
1421         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1422                                                                                                   TimeIntervalGetDatum(i)));
1423         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
1424 }
1425
1426 Datum
1427 tintervallenlt(PG_FUNCTION_ARGS)
1428 {
1429         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1430         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1431         RelativeTime rt;
1432
1433         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1434                 PG_RETURN_BOOL(false);
1435         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1436                                                                                                   TimeIntervalGetDatum(i)));
1437         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
1438 }
1439
1440 Datum
1441 tintervallengt(PG_FUNCTION_ARGS)
1442 {
1443         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1444         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1445         RelativeTime rt;
1446
1447         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1448                 PG_RETURN_BOOL(false);
1449         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1450                                                                                                   TimeIntervalGetDatum(i)));
1451         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
1452 }
1453
1454 Datum
1455 tintervallenle(PG_FUNCTION_ARGS)
1456 {
1457         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1458         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1459         RelativeTime rt;
1460
1461         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1462                 PG_RETURN_BOOL(false);
1463         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1464                                                                                                   TimeIntervalGetDatum(i)));
1465         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
1466 }
1467
1468 Datum
1469 tintervallenge(PG_FUNCTION_ARGS)
1470 {
1471         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1472         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1473         RelativeTime rt;
1474
1475         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1476                 PG_RETURN_BOOL(false);
1477         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1478                                                                                                   TimeIntervalGetDatum(i)));
1479         PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
1480 }
1481
1482 /*
1483  *              tintervalct             - returns true iff interval i1 contains interval i2
1484  */
1485 Datum
1486 tintervalct(PG_FUNCTION_ARGS)
1487 {
1488         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1489         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1490
1491         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1492                 PG_RETURN_BOOL(false);
1493         if (DatumGetBool(DirectFunctionCall2(abstimele,
1494                                                                                  AbsoluteTimeGetDatum(i1->data[0]),
1495                                                                                  AbsoluteTimeGetDatum(i2->data[0]))) &&
1496                 DatumGetBool(DirectFunctionCall2(abstimege,
1497                                                                                  AbsoluteTimeGetDatum(i1->data[1]),
1498                                                                                  AbsoluteTimeGetDatum(i2->data[1]))))
1499                 PG_RETURN_BOOL(true);
1500         PG_RETURN_BOOL(false);
1501 }
1502
1503 /*
1504  *              tintervalov             - returns true iff interval i1 (partially) overlaps i2
1505  */
1506 Datum
1507 tintervalov(PG_FUNCTION_ARGS)
1508 {
1509         TimeInterval    i1 = PG_GETARG_TIMEINTERVAL(0);
1510         TimeInterval    i2 = PG_GETARG_TIMEINTERVAL(1);
1511
1512         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1513                 PG_RETURN_BOOL(false);
1514         if (DatumGetBool(DirectFunctionCall2(abstimelt,
1515                                                                                  AbsoluteTimeGetDatum(i1->data[1]),
1516                                                                                  AbsoluteTimeGetDatum(i2->data[0]))) ||
1517                 DatumGetBool(DirectFunctionCall2(abstimegt,
1518                                                                                  AbsoluteTimeGetDatum(i1->data[0]),
1519                                                                                  AbsoluteTimeGetDatum(i2->data[1]))))
1520                 PG_RETURN_BOOL(false);
1521         PG_RETURN_BOOL(true);
1522 }
1523
1524 /*
1525  *              tintervalstart  - returns  the start of interval i
1526  */
1527 Datum
1528 tintervalstart(PG_FUNCTION_ARGS)
1529 {
1530         TimeInterval    i = PG_GETARG_TIMEINTERVAL(0);
1531
1532         if (i->status == T_INTERVAL_INVAL)
1533                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1534         PG_RETURN_ABSOLUTETIME(i->data[0]);
1535 }
1536
1537 /*
1538  *              tintervalend            - returns  the end of interval i
1539  */
1540 Datum
1541 tintervalend(PG_FUNCTION_ARGS)
1542 {
1543         TimeInterval    i = PG_GETARG_TIMEINTERVAL(0);
1544
1545         if (i->status == T_INTERVAL_INVAL)
1546                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1547         PG_RETURN_ABSOLUTETIME(i->data[1]);
1548 }
1549
1550
1551 /*****************************************************************************
1552  *       PRIVATE ROUTINES                                                                                                                *
1553  *****************************************************************************/
1554
1555 #ifdef NOT_USED
1556 /*
1557  *              isreltime               - returns 1, iff datestring is of type reltime
1558  *                                                                2, iff datestring is 'invalid time' identifier
1559  *                                                                0, iff datestring contains a syntax error
1560  *              VALID time      less or equal +/-  `@ 68 years'
1561  *
1562  */
1563 int
1564 isreltime(char *str)
1565 {
1566         struct tm       tt,
1567                            *tm = &tt;
1568         double          fsec;
1569         int                     dtype;
1570         char       *field[MAXDATEFIELDS];
1571         int                     nf,
1572                                 ftype[MAXDATEFIELDS];
1573         char            lowstr[MAXDATELEN + 1];
1574
1575         if (!PointerIsValid(str))
1576                 return 0;
1577
1578         if (strlen(str) > MAXDATELEN)
1579                 return 0;
1580
1581         if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
1582                 || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
1583                 return 0;
1584
1585         switch (dtype)
1586         {
1587                 case (DTK_DELTA):
1588                         return (abs(tm->tm_year) <= 68) ? 1 : 0;
1589                         break;
1590
1591                 case (DTK_INVALID):
1592                         return 2;
1593                         break;
1594
1595                 default:
1596                         return 0;
1597                         break;
1598         }
1599
1600         return 0;
1601 }       /* isreltime() */
1602
1603 #endif
1604
1605 #ifdef NOT_USED
1606 int
1607 dummyfunc()
1608 {
1609         char       *p;
1610         char            c;
1611         int                     i;
1612         char            unit[UNITMAXLEN];
1613         char            direction[DIRMAXLEN];
1614         int                     localSign;
1615         int                     localUnitNumber;
1616         long            localQuantity;
1617
1618         if (!PointerIsValid(sign))
1619                 sign = &localSign;
1620
1621         if (!PointerIsValid(unitnr))
1622                 unitnr = &localUnitNumber;
1623
1624         if (!PointerIsValid(quantity))
1625                 quantity = &localQuantity;
1626
1627         unit[0] = '\0';
1628         direction[0] = '\0';
1629         p = timestring;
1630         /* skip leading blanks */
1631         while ((c = *p) != '\0')
1632         {
1633                 if (c != ' ')
1634                         break;
1635                 p++;
1636         }
1637
1638         /* Test whether 'invalid time' identifier or not */
1639         if (!strncmp(INVALID_RELTIME_STR, p, strlen(INVALID_RELTIME_STR) + 1))
1640                 return 2;                               /* correct 'invalid time' identifier found */
1641
1642         /* handle label of relative time */
1643         if (c != RELTIME_LABEL)
1644                 return 0;                               /* syntax error */
1645         c = *++p;
1646         if (c != ' ')
1647                 return 0;                               /* syntax error */
1648         p++;
1649         /* handle the quantity */
1650         *quantity = 0;
1651         for (;;)
1652         {
1653                 c = *p;
1654                 if (isdigit((unsigned char) c))
1655                 {
1656                         *quantity = *quantity * 10 + (c - '0');
1657                         p++;
1658                 }
1659                 else
1660                 {
1661                         if (c == ' ')
1662                                 break;                  /* correct quantity found */
1663                         else
1664                                 return 0;               /* syntax error */
1665                 }
1666         }
1667
1668         /* handle unit */
1669         p++;
1670         i = 0;
1671         for (;;)
1672         {
1673                 c = *p;
1674                 if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1))
1675                 {
1676                         unit[i] = c;
1677                         p++;
1678                         i++;
1679                 }
1680                 else
1681                 {
1682                         if ((c == ' ' || c == '\0')
1683                                 && correct_unit(unit, unitnr))
1684                                 break;                  /* correct unit found */
1685                         else
1686                                 return 0;               /* syntax error */
1687                 }
1688         }
1689
1690         /* handle optional direction */
1691         if (c == ' ')
1692                 p++;
1693         i = 0;
1694         *sign = 1;
1695         for (;;)
1696         {
1697                 c = *p;
1698                 if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1))
1699                 {
1700                         direction[i] = c;
1701                         p++;
1702                         i++;
1703                 }
1704                 else
1705                 {
1706                         if ((c == ' ' || c == '\0') && i == 0)
1707                         {
1708                                 *sign = 1;
1709                                 break;                  /* no direction specified */
1710                         }
1711                         if ((c == ' ' || c == '\0') && i != 0)
1712                         {
1713                                 direction[i] = '\0';
1714                                 correct_dir(direction, sign);
1715                                 break;                  /* correct direction found */
1716                         }
1717                         else
1718                                 return 0;               /* syntax error */
1719                 }
1720         }
1721
1722         return 1;
1723 }
1724
1725 /*
1726  *              correct_unit    - returns 1, iff unit is a correct unit description
1727  *
1728  *              output parameter:
1729  *                              unptr: points to an integer which is the appropriate unit number
1730  *                                         (see function isreltime())
1731  */
1732 static int
1733 correct_unit(char *unit, int *unptr)
1734 {
1735         int                     j = 0;
1736
1737         while (j < NUNITS)
1738         {
1739                 if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0)
1740                 {
1741                         *unptr = j;
1742                         return 1;
1743                 }
1744                 j++;
1745         }
1746         return 0;                                       /* invalid unit descriptor */
1747 }
1748
1749 /*
1750  *              correct_dir             - returns 1, iff direction is a correct identifier
1751  *
1752  *              output parameter:
1753  *                              signptr: points to -1 if dir corresponds to past tense
1754  *                                               else  to 1
1755  */
1756 static int
1757 correct_dir(char *direction, int *signptr)
1758 {
1759         *signptr = 1;
1760         if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST) + 1) == 0)
1761         {
1762                 *signptr = -1;
1763                 return 1;
1764         }
1765         else
1766                 return 0;                               /* invalid direction descriptor */
1767 }
1768
1769 #endif
1770
1771 /*
1772  *              istinterval             - returns 1, iff i_string is a valid interval descr.
1773  *                                                                0, iff i_string is NOT a valid interval desc.
1774  *                                                                2, iff any time is INVALID_ABSTIME
1775  *
1776  *              output parameter:
1777  *                              i_start, i_end: interval margins
1778  *
1779  *              Time interval:
1780  *              `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1781  *
1782  *              OR      `Undefined Range'       (see also INVALID_INTERVAL_STR)
1783  *
1784  *              where <AbsTime> satisfies the syntax of absolute time.
1785  *
1786  *              e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
1787  */
1788 static int
1789 istinterval(char *i_string,
1790                         AbsoluteTime *i_start,
1791                         AbsoluteTime *i_end)
1792 {
1793         char       *p,
1794                            *p1;
1795         char            c;
1796
1797         p = i_string;
1798         /* skip leading blanks up to '[' */
1799         while ((c = *p) != '\0')
1800         {
1801                 if (IsSpace(c))
1802                         p++;
1803                 else if (c != '[')
1804                         return 0;                       /* syntax error */
1805                 else
1806                         break;
1807         }
1808         p++;
1809         /* skip leading blanks up to "'" */
1810         while ((c = *p) != '\0')
1811         {
1812                 if (IsSpace(c))
1813                         p++;
1814                 else if (c != '"')
1815                         return 0;                       /* syntax error */
1816                 else
1817                         break;
1818         }
1819         p++;
1820         if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1821                 return 0;                               /* undefined range, handled like a syntax
1822                                                                  * err. */
1823         /* search for the end of the first date and change it to a NULL */
1824         p1 = p;
1825         while ((c = *p1) != '\0')
1826         {
1827                 if (c == '"')
1828                 {
1829                         *p1 = '\0';
1830                         break;
1831                 }
1832                 p1++;
1833         }
1834         /* get the first date */
1835         *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1836                                                                         CStringGetDatum(p)));
1837         /* rechange NULL at the end of the first date to a "'" */
1838         *p1 = '"';
1839         p = ++p1;
1840         /* skip blanks up to "'", beginning of second date */
1841         while ((c = *p) != '\0')
1842         {
1843                 if (IsSpace(c))
1844                         p++;
1845                 else if (c != '"')
1846                         return 0;                       /* syntax error */
1847                 else
1848                         break;
1849         }
1850         p++;
1851         /* search for the end of the second date and change it to a NULL */
1852         p1 = p;
1853         while ((c = *p1) != '\0')
1854         {
1855                 if (c == '"')
1856                 {
1857                         *p1 = '\0';
1858                         break;
1859                 }
1860                 p1++;
1861         }
1862         /* get the second date */
1863         *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
1864                                                                   CStringGetDatum(p)));
1865         /* rechange NULL at the end of the first date to a ''' */
1866         *p1 = '"';
1867         p = ++p1;
1868         /* skip blanks up to ']' */
1869         while ((c = *p) != '\0')
1870         {
1871                 if (IsSpace(c))
1872                         p++;
1873                 else if (c != ']')
1874                         return 0;                       /* syntax error */
1875                 else
1876                         break;
1877         }
1878         p++;
1879         c = *p;
1880         if (c != '\0')
1881                 return 0;                               /* syntax error */
1882         /* it seems to be a valid interval */
1883         return 1;
1884 }
1885
1886
1887 /*****************************************************************************
1888  *
1889  *****************************************************************************/
1890
1891 Datum
1892 int4reltime(PG_FUNCTION_ARGS)
1893 {
1894         int32           timevalue = PG_GETARG_INT32(0);
1895
1896         /* Just coerce it directly to RelativeTime ... */
1897         PG_RETURN_RELATIVETIME((RelativeTime) timevalue);
1898 }
1899
1900 /*
1901  * timeofday -
1902  *         returns the current time as a text. similar to timenow() but returns
1903  *         seconds with more precision (up to microsecs). (I need this to compare
1904  *         the Wisconsin benchmark with Illustra whose TimeNow() shows current
1905  *         time with precision up to microsecs.)                          - ay 3/95
1906  */
1907 Datum
1908 timeofday(PG_FUNCTION_ARGS)
1909 {
1910         struct timeval tp;
1911         struct timezone tpz;
1912         char            templ[500];
1913         char            buf[500];
1914         text       *result;
1915         int                     len = 0;
1916
1917         gettimeofday(&tp, &tpz);
1918         strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z",
1919                          localtime((time_t *) &tp.tv_sec));
1920         snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1921
1922         len = VARHDRSZ + strlen(buf);
1923         result = (text *) palloc(len);
1924         VARATT_SIZEP(result) = len;
1925         memcpy(VARDATA(result), buf, strlen(buf));
1926         PG_RETURN_TEXT_P(result);
1927 }