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