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