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