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