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