]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/nabstime.c
Create a 'type cache' that keeps track of the data needed for any particular
[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-2003, 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.114 2003/08/17 19:58:05 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, "\"]");
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  * reltime comparison routines
1194  */
1195 static int
1196 reltime_cmp_internal(RelativeTime a, RelativeTime b)
1197 {
1198         /*
1199          * We consider all INVALIDs to be equal and larger than any non-INVALID.
1200          * This is somewhat arbitrary; the important thing is to have a
1201          * consistent sort order.
1202          */
1203         if (a == INVALID_RELTIME)
1204         {
1205                 if (b == INVALID_RELTIME)
1206                         return 0;                       /* INVALID = INVALID */
1207                 else
1208                         return 1;                       /* INVALID > non-INVALID */
1209         }
1210
1211         if (b == INVALID_RELTIME)
1212                 return -1;                              /* non-INVALID < INVALID */
1213
1214         if (a > b)
1215                 return 1;
1216         else if (a == b)
1217                 return 0;
1218         else
1219                 return -1;
1220 }
1221
1222 Datum
1223 reltimeeq(PG_FUNCTION_ARGS)
1224 {
1225         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1226         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1227
1228         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
1229 }
1230
1231 Datum
1232 reltimene(PG_FUNCTION_ARGS)
1233 {
1234         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1235         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1236
1237         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
1238 }
1239
1240 Datum
1241 reltimelt(PG_FUNCTION_ARGS)
1242 {
1243         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1244         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1245
1246         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
1247 }
1248
1249 Datum
1250 reltimegt(PG_FUNCTION_ARGS)
1251 {
1252         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1253         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1254
1255         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
1256 }
1257
1258 Datum
1259 reltimele(PG_FUNCTION_ARGS)
1260 {
1261         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1262         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1263
1264         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
1265 }
1266
1267 Datum
1268 reltimege(PG_FUNCTION_ARGS)
1269 {
1270         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1271         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1272
1273         PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
1274 }
1275
1276 Datum
1277 btreltimecmp(PG_FUNCTION_ARGS)
1278 {
1279         RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
1280         RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
1281
1282         PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
1283 }
1284
1285
1286 /*
1287  *              tintervalsame   - returns true iff interval i1 is same as interval i2
1288  *              Check begin and end time.
1289  */
1290 Datum
1291 tintervalsame(PG_FUNCTION_ARGS)
1292 {
1293         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1294         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1295
1296         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1297                 PG_RETURN_BOOL(false);
1298
1299         if (DatumGetBool(DirectFunctionCall2(abstimeeq,
1300                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1301                                                                    AbsoluteTimeGetDatum(i2->data[0]))) &&
1302                 DatumGetBool(DirectFunctionCall2(abstimeeq,
1303                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1304                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1305                 PG_RETURN_BOOL(true);
1306         PG_RETURN_BOOL(false);
1307 }
1308
1309 /*
1310  * tinterval comparison routines
1311  *
1312  * Note: comparison is based on the lengths of the intervals, not on
1313  * endpoint value.  This is pretty bogus, but since it's only a legacy
1314  * datatype I'm not going to propose changing it.
1315  */
1316 static int
1317 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
1318 {
1319         bool            a_invalid;
1320         bool            b_invalid;
1321         AbsoluteTime a_len;
1322         AbsoluteTime b_len;
1323
1324         /*
1325          * We consider all INVALIDs to be equal and larger than any non-INVALID.
1326          * This is somewhat arbitrary; the important thing is to have a
1327          * consistent sort order.
1328          */
1329         a_invalid = ((a->status == T_INTERVAL_INVAL) ||
1330                                  (a->data[0] == INVALID_ABSTIME) ||
1331                                  (a->data[1] == INVALID_ABSTIME));
1332         b_invalid = ((b->status == T_INTERVAL_INVAL) ||
1333                                  (b->data[0] == INVALID_ABSTIME) ||
1334                                  (b->data[1] == INVALID_ABSTIME));
1335
1336         if (a_invalid)
1337         {
1338                 if (b_invalid)
1339                         return 0;                       /* INVALID = INVALID */
1340                 else
1341                         return 1;                       /* INVALID > non-INVALID */
1342         }
1343
1344         if (b_invalid)
1345                 return -1;                              /* non-INVALID < INVALID */
1346
1347         a_len = a->data[1] - a->data[0];
1348         b_len = b->data[1] - b->data[0];
1349
1350         if (a_len > b_len)
1351                 return 1;
1352         else if (a_len == b_len)
1353                 return 0;
1354         else
1355                 return -1;
1356 }
1357
1358 Datum
1359 tintervaleq(PG_FUNCTION_ARGS)
1360 {
1361         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1362         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1363
1364         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
1365 }
1366
1367 Datum
1368 tintervalne(PG_FUNCTION_ARGS)
1369 {
1370         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1371         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1372
1373         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
1374 }
1375
1376 Datum
1377 tintervallt(PG_FUNCTION_ARGS)
1378 {
1379         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1380         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1381
1382         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
1383 }
1384
1385 Datum
1386 tintervalle(PG_FUNCTION_ARGS)
1387 {
1388         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1389         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1390
1391         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
1392 }
1393
1394 Datum
1395 tintervalgt(PG_FUNCTION_ARGS)
1396 {
1397         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1398         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1399
1400         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
1401 }
1402
1403 Datum
1404 tintervalge(PG_FUNCTION_ARGS)
1405 {
1406         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1407         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1408
1409         PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
1410 }
1411
1412 Datum
1413 bttintervalcmp(PG_FUNCTION_ARGS)
1414 {
1415         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1416         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1417
1418         PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
1419 }
1420
1421
1422 /*
1423  *              tintervalleneq  - returns true iff length of interval i is equal to
1424  *                                                              reltime t
1425  *              tintervallenne  - returns true iff length of interval i is not equal
1426  *                                                              to reltime t
1427  *              tintervallenlt  - returns true iff length of interval i is less than
1428  *                                                              reltime t
1429  *              tintervallengt  - returns true iff length of interval i is greater
1430  *                                                              than reltime t
1431  *              tintervallenle  - returns true iff length of interval i is less or
1432  *                                                              equal than reltime t
1433  *              tintervallenge  - returns true iff length of interval i is greater or
1434  *                                                              equal than reltime t
1435  */
1436 Datum
1437 tintervalleneq(PG_FUNCTION_ARGS)
1438 {
1439         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1440         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1441         RelativeTime rt;
1442
1443         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1444                 PG_RETURN_BOOL(false);
1445         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1446                                                                                            TimeIntervalGetDatum(i)));
1447         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt == t));
1448 }
1449
1450 Datum
1451 tintervallenne(PG_FUNCTION_ARGS)
1452 {
1453         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1454         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1455         RelativeTime rt;
1456
1457         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1458                 PG_RETURN_BOOL(false);
1459         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1460                                                                                            TimeIntervalGetDatum(i)));
1461         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt != t));
1462 }
1463
1464 Datum
1465 tintervallenlt(PG_FUNCTION_ARGS)
1466 {
1467         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1468         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1469         RelativeTime rt;
1470
1471         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1472                 PG_RETURN_BOOL(false);
1473         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1474                                                                                            TimeIntervalGetDatum(i)));
1475         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt < t));
1476 }
1477
1478 Datum
1479 tintervallengt(PG_FUNCTION_ARGS)
1480 {
1481         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1482         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1483         RelativeTime rt;
1484
1485         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1486                 PG_RETURN_BOOL(false);
1487         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1488                                                                                            TimeIntervalGetDatum(i)));
1489         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt > t));
1490 }
1491
1492 Datum
1493 tintervallenle(PG_FUNCTION_ARGS)
1494 {
1495         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1496         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1497         RelativeTime rt;
1498
1499         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1500                 PG_RETURN_BOOL(false);
1501         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1502                                                                                            TimeIntervalGetDatum(i)));
1503         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt <= t));
1504 }
1505
1506 Datum
1507 tintervallenge(PG_FUNCTION_ARGS)
1508 {
1509         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1510         RelativeTime t = PG_GETARG_RELATIVETIME(1);
1511         RelativeTime rt;
1512
1513         if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
1514                 PG_RETURN_BOOL(false);
1515         rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
1516                                                                                            TimeIntervalGetDatum(i)));
1517         PG_RETURN_BOOL((rt != INVALID_RELTIME) && (rt >= t));
1518 }
1519
1520 /*
1521  *              tintervalct             - returns true iff interval i1 contains interval i2
1522  */
1523 Datum
1524 tintervalct(PG_FUNCTION_ARGS)
1525 {
1526         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1527         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1528
1529         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1530                 PG_RETURN_BOOL(false);
1531         if (DatumGetBool(DirectFunctionCall2(abstimele,
1532                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1533                                                                    AbsoluteTimeGetDatum(i2->data[0]))) &&
1534                 DatumGetBool(DirectFunctionCall2(abstimege,
1535                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1536                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1537                 PG_RETURN_BOOL(true);
1538         PG_RETURN_BOOL(false);
1539 }
1540
1541 /*
1542  *              tintervalov             - returns true iff interval i1 (partially) overlaps i2
1543  */
1544 Datum
1545 tintervalov(PG_FUNCTION_ARGS)
1546 {
1547         TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
1548         TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
1549
1550         if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
1551                 PG_RETURN_BOOL(false);
1552         if (DatumGetBool(DirectFunctionCall2(abstimelt,
1553                                                                            AbsoluteTimeGetDatum(i1->data[1]),
1554                                                                    AbsoluteTimeGetDatum(i2->data[0]))) ||
1555                 DatumGetBool(DirectFunctionCall2(abstimegt,
1556                                                                            AbsoluteTimeGetDatum(i1->data[0]),
1557                                                                          AbsoluteTimeGetDatum(i2->data[1]))))
1558                 PG_RETURN_BOOL(false);
1559         PG_RETURN_BOOL(true);
1560 }
1561
1562 /*
1563  *              tintervalstart  - returns  the start of interval i
1564  */
1565 Datum
1566 tintervalstart(PG_FUNCTION_ARGS)
1567 {
1568         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1569
1570         if (i->status == T_INTERVAL_INVAL)
1571                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1572         PG_RETURN_ABSOLUTETIME(i->data[0]);
1573 }
1574
1575 /*
1576  *              tintervalend            - returns  the end of interval i
1577  */
1578 Datum
1579 tintervalend(PG_FUNCTION_ARGS)
1580 {
1581         TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
1582
1583         if (i->status == T_INTERVAL_INVAL)
1584                 PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
1585         PG_RETURN_ABSOLUTETIME(i->data[1]);
1586 }
1587
1588
1589 /*****************************************************************************
1590  *       PRIVATE ROUTINES                                                                                                                *
1591  *****************************************************************************/
1592
1593 /*
1594  *              istinterval             - returns 1, iff i_string is a valid interval descr.
1595  *                                                                0, iff i_string is NOT a valid interval desc.
1596  *                                                                2, iff any time is INVALID_ABSTIME
1597  *
1598  *              output parameter:
1599  *                              i_start, i_end: interval margins
1600  *
1601  *              Time interval:
1602  *              `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
1603  *
1604  *              OR      `Undefined Range'       (see also INVALID_INTERVAL_STR)
1605  *
1606  *              where <AbsTime> satisfies the syntax of absolute time.
1607  *
1608  *              e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
1609  */
1610 static int
1611 istinterval(char *i_string,
1612                         AbsoluteTime *i_start,
1613                         AbsoluteTime *i_end)
1614 {
1615         char       *p,
1616                            *p1;
1617         char            c;
1618
1619         p = i_string;
1620         /* skip leading blanks up to '[' */
1621         while ((c = *p) != '\0')
1622         {
1623                 if (IsSpace(c))
1624                         p++;
1625                 else if (c != '[')
1626                         return 0;                       /* syntax error */
1627                 else
1628                         break;
1629         }
1630         p++;
1631         /* skip leading blanks up to '"' */
1632         while ((c = *p) != '\0')
1633         {
1634                 if (IsSpace(c))
1635                         p++;
1636                 else if (c != '"')
1637                         return 0;                       /* syntax error */
1638                 else
1639                         break;
1640         }
1641         p++;
1642         if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
1643                 return 0;                               /* undefined range, handled like a syntax
1644                                                                  * err. */
1645         /* search for the end of the first date and change it to a NULL */
1646         p1 = p;
1647         while ((c = *p1) != '\0')
1648         {
1649                 if (c == '"')
1650                 {
1651                         *p1 = '\0';
1652                         break;
1653                 }
1654                 p1++;
1655         }
1656         /* get the first date */
1657         *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1658                                                                                                         CStringGetDatum(p)));
1659         /* rechange NULL at the end of the first date to a '"' */
1660         *p1 = '"';
1661         p = ++p1;
1662         /* skip blanks up to '"', beginning of second date */
1663         while ((c = *p) != '\0')
1664         {
1665                 if (IsSpace(c))
1666                         p++;
1667                 else if (c != '"')
1668                         return 0;                       /* syntax error */
1669                 else
1670                         break;
1671         }
1672         p++;
1673         /* search for the end of the second date and change it to a NULL */
1674         p1 = p;
1675         while ((c = *p1) != '\0')
1676         {
1677                 if (c == '"')
1678                 {
1679                         *p1 = '\0';
1680                         break;
1681                 }
1682                 p1++;
1683         }
1684         /* get the second date */
1685         *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
1686                                                                                                         CStringGetDatum(p)));
1687         /* rechange NULL at the end of the first date to a '"' */
1688         *p1 = '"';
1689         p = ++p1;
1690         /* skip blanks up to ']' */
1691         while ((c = *p) != '\0')
1692         {
1693                 if (IsSpace(c))
1694                         p++;
1695                 else if (c != ']')
1696                         return 0;                       /* syntax error */
1697                 else
1698                         break;
1699         }
1700         p++;
1701         c = *p;
1702         if (c != '\0')
1703                 return 0;                               /* syntax error */
1704         /* it seems to be a valid interval */
1705         return 1;
1706 }
1707
1708
1709 /*****************************************************************************
1710  *
1711  *****************************************************************************/
1712
1713 /*
1714  * timeofday -
1715  *         returns the current time as a text. similar to timenow() but returns
1716  *         seconds with more precision (up to microsecs). (I need this to compare
1717  *         the Wisconsin benchmark with Illustra whose TimeNow() shows current
1718  *         time with precision up to microsecs.)                          - ay 3/95
1719  */
1720 Datum
1721 timeofday(PG_FUNCTION_ARGS)
1722 {
1723         struct timeval tp;
1724         struct timezone tpz;
1725         char            templ[100];
1726         char            buf[100];
1727         text       *result;
1728         int                     len;
1729
1730         gettimeofday(&tp, &tpz);
1731         strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
1732                          localtime((time_t *) &tp.tv_sec));
1733         snprintf(buf, sizeof(buf), templ, tp.tv_usec);
1734
1735         len = VARHDRSZ + strlen(buf);
1736         result = (text *) palloc(len);
1737         VARATT_SIZEP(result) = len;
1738         memcpy(VARDATA(result), buf, strlen(buf));
1739         PG_RETURN_TEXT_P(result);
1740 }