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