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