Header And Logo

PostgreSQL
| The world's most advanced open source database.

nabstime.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nabstime.c
00004  *    Utilities for the built-in type "AbsoluteTime".
00005  *    Functions for the built-in type "RelativeTime".
00006  *    Functions for the built-in type "TimeInterval".
00007  *
00008  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00009  * Portions Copyright (c) 1994, Regents of the University of California
00010  *
00011  *
00012  * IDENTIFICATION
00013  *    src/backend/utils/adt/nabstime.c
00014  *
00015  *-------------------------------------------------------------------------
00016  */
00017 #include "postgres.h"
00018 
00019 #include <ctype.h>
00020 #include <float.h>
00021 #include <limits.h>
00022 #include <time.h>
00023 #include <sys/time.h>
00024 
00025 #include "libpq/pqformat.h"
00026 #include "miscadmin.h"
00027 #include "utils/builtins.h"
00028 #include "utils/datetime.h"
00029 #include "utils/nabstime.h"
00030 
00031 #define MIN_DAYNUM (-24856)     /* December 13, 1901 */
00032 #define MAX_DAYNUM 24854        /* January 18, 2038 */
00033 
00034 /*
00035  * Unix epoch is Jan  1 00:00:00 1970.
00036  * Postgres knows about times sixty-eight years on either side of that
00037  * for these 4-byte types.
00038  *
00039  * "tinterval" is two 4-byte fields.
00040  * Definitions for parsing tinterval.
00041  */
00042 
00043 #define IsSpace(C)              ((C) == ' ')
00044 
00045 #define T_INTERVAL_INVAL   0    /* data represents no valid tinterval */
00046 #define T_INTERVAL_VALID   1    /* data represents a valid tinterval */
00047 /*
00048  * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
00049  * 0        1         2         3         4         5         6
00050  * 1234567890123456789012345678901234567890123456789012345678901234
00051  *
00052  * we allocate some extra -- timezones are usually 3 characters but
00053  * this is not in the POSIX standard...
00054  */
00055 #define T_INTERVAL_LEN                  80
00056 #define INVALID_INTERVAL_STR            "Undefined Range"
00057 #define INVALID_INTERVAL_STR_LEN        (sizeof(INVALID_INTERVAL_STR)-1)
00058 
00059 #define ABSTIMEMIN(t1, t2) \
00060     (DatumGetBool(DirectFunctionCall2(abstimele, \
00061                   AbsoluteTimeGetDatum(t1), \
00062                   AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
00063 #define ABSTIMEMAX(t1, t2) \
00064     (DatumGetBool(DirectFunctionCall2(abstimelt, \
00065                   AbsoluteTimeGetDatum(t1), \
00066                   AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
00067 
00068 
00069 /*
00070  * Function prototypes -- internal to this file only
00071  */
00072 
00073 static AbsoluteTime tm2abstime(struct pg_tm * tm, int tz);
00074 static void reltime2tm(RelativeTime time, struct pg_tm * tm);
00075 static void parsetinterval(char *i_string,
00076                AbsoluteTime *i_start,
00077                AbsoluteTime *i_end);
00078 
00079 
00080 /*
00081  * GetCurrentAbsoluteTime()
00082  *
00083  * Get the current system time (relative to Unix epoch).
00084  *
00085  * NB: this will overflow in 2038; it should be gone long before that.
00086  */
00087 AbsoluteTime
00088 GetCurrentAbsoluteTime(void)
00089 {
00090     time_t      now;
00091 
00092     now = time(NULL);
00093     return (AbsoluteTime) now;
00094 }
00095 
00096 
00097 void
00098 abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
00099 {
00100     pg_time_t   time = (pg_time_t) _time;
00101     struct pg_tm *tx;
00102 
00103     /*
00104      * If HasCTZSet is true then we have a brute force time zone specified. Go
00105      * ahead and rotate to the local time zone since we will later bypass any
00106      * calls which adjust the tm fields.
00107      */
00108     if (HasCTZSet && (tzp != NULL))
00109         time -= CTimeZone;
00110 
00111     if (!HasCTZSet && tzp != NULL)
00112         tx = pg_localtime(&time, session_timezone);
00113     else
00114         tx = pg_gmtime(&time);
00115 
00116     tm->tm_year = tx->tm_year + 1900;
00117     tm->tm_mon = tx->tm_mon + 1;
00118     tm->tm_mday = tx->tm_mday;
00119     tm->tm_hour = tx->tm_hour;
00120     tm->tm_min = tx->tm_min;
00121     tm->tm_sec = tx->tm_sec;
00122     tm->tm_isdst = tx->tm_isdst;
00123 
00124     tm->tm_gmtoff = tx->tm_gmtoff;
00125     tm->tm_zone = tx->tm_zone;
00126 
00127     if (tzp != NULL)
00128     {
00129         /*
00130          * We have a brute force time zone per SQL99? Then use it without
00131          * change since we have already rotated to the time zone.
00132          */
00133         if (HasCTZSet)
00134         {
00135             *tzp = CTimeZone;
00136             tm->tm_gmtoff = CTimeZone;
00137             tm->tm_isdst = 0;
00138             tm->tm_zone = NULL;
00139             if (tzn != NULL)
00140                 *tzn = NULL;
00141         }
00142         else
00143         {
00144             *tzp = -tm->tm_gmtoff;      /* tm_gmtoff is Sun/DEC-ism */
00145 
00146             /*
00147              * XXX FreeBSD man pages indicate that this should work - tgl
00148              * 97/04/23
00149              */
00150             if (tzn != NULL)
00151             {
00152                 /*
00153                  * Copy no more than MAXTZLEN bytes of timezone to tzn, in
00154                  * case it contains an error message, which doesn't fit in the
00155                  * buffer
00156                  */
00157                 StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
00158                 if (strlen(tm->tm_zone) > MAXTZLEN)
00159                     ereport(WARNING,
00160                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00161                              errmsg("invalid time zone name: \"%s\"",
00162                                     tm->tm_zone)));
00163             }
00164         }
00165     }
00166     else
00167         tm->tm_isdst = -1;
00168 }
00169 
00170 
00171 /* tm2abstime()
00172  * Convert a tm structure to abstime.
00173  * Note that tm has full year (not 1900-based) and 1-based month.
00174  */
00175 static AbsoluteTime
00176 tm2abstime(struct pg_tm * tm, int tz)
00177 {
00178     int         day;
00179     AbsoluteTime sec;
00180 
00181     /* validate, before going out of range on some members */
00182     if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
00183         tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
00184         tm->tm_mday < 1 || tm->tm_mday > 31 ||
00185         tm->tm_hour < 0 ||
00186         tm->tm_hour > HOURS_PER_DAY ||  /* test for > 24:00:00 */
00187       (tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
00188         tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
00189         tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
00190         return INVALID_ABSTIME;
00191 
00192     day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
00193 
00194     /* check for time out of range */
00195     if (day < MIN_DAYNUM || day > MAX_DAYNUM)
00196         return INVALID_ABSTIME;
00197 
00198     /* convert to seconds */
00199     sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE;
00200 
00201     /*
00202      * check for overflow.  We need a little slop here because the H/M/S plus
00203      * TZ offset could add up to more than 1 day.
00204      */
00205     if ((day >= MAX_DAYNUM - 10 && sec < 0) ||
00206         (day <= MIN_DAYNUM + 10 && sec > 0))
00207         return INVALID_ABSTIME;
00208 
00209     /* check for reserved values (e.g. "current" on edge of usual range */
00210     if (!AbsoluteTimeIsReal(sec))
00211         return INVALID_ABSTIME;
00212 
00213     return sec;
00214 }
00215 
00216 
00217 /* abstimein()
00218  * Decode date/time string and return abstime.
00219  */
00220 Datum
00221 abstimein(PG_FUNCTION_ARGS)
00222 {
00223     char       *str = PG_GETARG_CSTRING(0);
00224     AbsoluteTime result;
00225     fsec_t      fsec;
00226     int         tz = 0;
00227     struct pg_tm date,
00228                *tm = &date;
00229     int         dterr;
00230     char       *field[MAXDATEFIELDS];
00231     char        workbuf[MAXDATELEN + 1];
00232     int         dtype;
00233     int         nf,
00234                 ftype[MAXDATEFIELDS];
00235 
00236     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
00237                           field, ftype, MAXDATEFIELDS, &nf);
00238     if (dterr == 0)
00239         dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
00240     if (dterr != 0)
00241         DateTimeParseError(dterr, str, "abstime");
00242 
00243     switch (dtype)
00244     {
00245         case DTK_DATE:
00246             result = tm2abstime(tm, tz);
00247             break;
00248 
00249         case DTK_EPOCH:
00250 
00251             /*
00252              * Don't bother retaining this as a reserved value, but instead
00253              * just set to the actual epoch time (1970-01-01)
00254              */
00255             result = 0;
00256             break;
00257 
00258         case DTK_LATE:
00259             result = NOEND_ABSTIME;
00260             break;
00261 
00262         case DTK_EARLY:
00263             result = NOSTART_ABSTIME;
00264             break;
00265 
00266         case DTK_INVALID:
00267             result = INVALID_ABSTIME;
00268             break;
00269 
00270         default:
00271             elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
00272                  dtype, str);
00273             result = INVALID_ABSTIME;
00274             break;
00275     };
00276 
00277     PG_RETURN_ABSOLUTETIME(result);
00278 }
00279 
00280 
00281 /* abstimeout()
00282  * Given an AbsoluteTime return the English text version of the date
00283  */
00284 Datum
00285 abstimeout(PG_FUNCTION_ARGS)
00286 {
00287     AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
00288     char       *result;
00289     int         tz;
00290     double      fsec = 0;
00291     struct pg_tm tt,
00292                *tm = &tt;
00293     char        buf[MAXDATELEN + 1];
00294     char        zone[MAXDATELEN + 1],
00295                *tzn = zone;
00296 
00297     switch (time)
00298     {
00299             /*
00300              * Note that timestamp no longer supports 'invalid'. Retain
00301              * 'invalid' for abstime for now, but dump it someday.
00302              */
00303         case INVALID_ABSTIME:
00304             strcpy(buf, INVALID);
00305             break;
00306         case NOEND_ABSTIME:
00307             strcpy(buf, LATE);
00308             break;
00309         case NOSTART_ABSTIME:
00310             strcpy(buf, EARLY);
00311             break;
00312         default:
00313             abstime2tm(time, &tz, tm, &tzn);
00314             EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
00315             break;
00316     }
00317 
00318     result = pstrdup(buf);
00319     PG_RETURN_CSTRING(result);
00320 }
00321 
00322 /*
00323  *      abstimerecv         - converts external binary format to abstime
00324  */
00325 Datum
00326 abstimerecv(PG_FUNCTION_ARGS)
00327 {
00328     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00329 
00330     PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
00331 }
00332 
00333 /*
00334  *      abstimesend         - converts abstime to binary format
00335  */
00336 Datum
00337 abstimesend(PG_FUNCTION_ARGS)
00338 {
00339     AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
00340     StringInfoData buf;
00341 
00342     pq_begintypsend(&buf);
00343     pq_sendint(&buf, time, sizeof(time));
00344     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00345 }
00346 
00347 
00348 /* abstime_finite()
00349  */
00350 Datum
00351 abstime_finite(PG_FUNCTION_ARGS)
00352 {
00353     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
00354 
00355     PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
00356                    abstime != NOSTART_ABSTIME &&
00357                    abstime != NOEND_ABSTIME);
00358 }
00359 
00360 
00361 /*
00362  * abstime comparison routines
00363  */
00364 static int
00365 abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
00366 {
00367     /*
00368      * We consider all INVALIDs to be equal and larger than any non-INVALID.
00369      * This is somewhat arbitrary; the important thing is to have a consistent
00370      * sort order.
00371      */
00372     if (a == INVALID_ABSTIME)
00373     {
00374         if (b == INVALID_ABSTIME)
00375             return 0;           /* INVALID = INVALID */
00376         else
00377             return 1;           /* INVALID > non-INVALID */
00378     }
00379 
00380     if (b == INVALID_ABSTIME)
00381         return -1;              /* non-INVALID < INVALID */
00382 
00383     if (a > b)
00384         return 1;
00385     else if (a == b)
00386         return 0;
00387     else
00388         return -1;
00389 }
00390 
00391 Datum
00392 abstimeeq(PG_FUNCTION_ARGS)
00393 {
00394     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00395     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00396 
00397     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
00398 }
00399 
00400 Datum
00401 abstimene(PG_FUNCTION_ARGS)
00402 {
00403     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00404     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00405 
00406     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
00407 }
00408 
00409 Datum
00410 abstimelt(PG_FUNCTION_ARGS)
00411 {
00412     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00413     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00414 
00415     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
00416 }
00417 
00418 Datum
00419 abstimegt(PG_FUNCTION_ARGS)
00420 {
00421     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00422     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00423 
00424     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
00425 }
00426 
00427 Datum
00428 abstimele(PG_FUNCTION_ARGS)
00429 {
00430     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00431     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00432 
00433     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
00434 }
00435 
00436 Datum
00437 abstimege(PG_FUNCTION_ARGS)
00438 {
00439     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00440     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00441 
00442     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
00443 }
00444 
00445 Datum
00446 btabstimecmp(PG_FUNCTION_ARGS)
00447 {
00448     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00449     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00450 
00451     PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
00452 }
00453 
00454 
00455 /* timestamp_abstime()
00456  * Convert timestamp to abstime.
00457  */
00458 Datum
00459 timestamp_abstime(PG_FUNCTION_ARGS)
00460 {
00461     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
00462     AbsoluteTime result;
00463     fsec_t      fsec;
00464     int         tz;
00465     struct pg_tm tt,
00466                *tm = &tt;
00467 
00468     if (TIMESTAMP_IS_NOBEGIN(timestamp))
00469         result = NOSTART_ABSTIME;
00470     else if (TIMESTAMP_IS_NOEND(timestamp))
00471         result = NOEND_ABSTIME;
00472     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
00473     {
00474         tz = DetermineTimeZoneOffset(tm, session_timezone);
00475         result = tm2abstime(tm, tz);
00476     }
00477     else
00478     {
00479         ereport(ERROR,
00480                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00481                  errmsg("timestamp out of range")));
00482         result = INVALID_ABSTIME;
00483     }
00484 
00485     PG_RETURN_ABSOLUTETIME(result);
00486 }
00487 
00488 /* abstime_timestamp()
00489  * Convert abstime to timestamp.
00490  */
00491 Datum
00492 abstime_timestamp(PG_FUNCTION_ARGS)
00493 {
00494     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
00495     Timestamp   result;
00496     struct pg_tm tt,
00497                *tm = &tt;
00498     int         tz;
00499     char        zone[MAXDATELEN + 1],
00500                *tzn = zone;
00501 
00502     switch (abstime)
00503     {
00504         case INVALID_ABSTIME:
00505             ereport(ERROR,
00506                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00507                  errmsg("cannot convert abstime \"invalid\" to timestamp")));
00508             TIMESTAMP_NOBEGIN(result);
00509             break;
00510 
00511         case NOSTART_ABSTIME:
00512             TIMESTAMP_NOBEGIN(result);
00513             break;
00514 
00515         case NOEND_ABSTIME:
00516             TIMESTAMP_NOEND(result);
00517             break;
00518 
00519         default:
00520             abstime2tm(abstime, &tz, tm, &tzn);
00521             if (tm2timestamp(tm, 0, NULL, &result) != 0)
00522                 ereport(ERROR,
00523                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00524                          errmsg("timestamp out of range")));
00525             break;
00526     };
00527 
00528     PG_RETURN_TIMESTAMP(result);
00529 }
00530 
00531 
00532 /* timestamptz_abstime()
00533  * Convert timestamp with time zone to abstime.
00534  */
00535 Datum
00536 timestamptz_abstime(PG_FUNCTION_ARGS)
00537 {
00538     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
00539     AbsoluteTime result;
00540     fsec_t      fsec;
00541     struct pg_tm tt,
00542                *tm = &tt;
00543 
00544     if (TIMESTAMP_IS_NOBEGIN(timestamp))
00545         result = NOSTART_ABSTIME;
00546     else if (TIMESTAMP_IS_NOEND(timestamp))
00547         result = NOEND_ABSTIME;
00548     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
00549         result = tm2abstime(tm, 0);
00550     else
00551     {
00552         ereport(ERROR,
00553                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00554                  errmsg("timestamp out of range")));
00555         result = INVALID_ABSTIME;
00556     }
00557 
00558     PG_RETURN_ABSOLUTETIME(result);
00559 }
00560 
00561 /* abstime_timestamptz()
00562  * Convert abstime to timestamp with time zone.
00563  */
00564 Datum
00565 abstime_timestamptz(PG_FUNCTION_ARGS)
00566 {
00567     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
00568     TimestampTz result;
00569     struct pg_tm tt,
00570                *tm = &tt;
00571     int         tz;
00572     char        zone[MAXDATELEN + 1],
00573                *tzn = zone;
00574 
00575     switch (abstime)
00576     {
00577         case INVALID_ABSTIME:
00578             ereport(ERROR,
00579                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00580                  errmsg("cannot convert abstime \"invalid\" to timestamp")));
00581             TIMESTAMP_NOBEGIN(result);
00582             break;
00583 
00584         case NOSTART_ABSTIME:
00585             TIMESTAMP_NOBEGIN(result);
00586             break;
00587 
00588         case NOEND_ABSTIME:
00589             TIMESTAMP_NOEND(result);
00590             break;
00591 
00592         default:
00593             abstime2tm(abstime, &tz, tm, &tzn);
00594             if (tm2timestamp(tm, 0, &tz, &result) != 0)
00595                 ereport(ERROR,
00596                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
00597                          errmsg("timestamp out of range")));
00598             break;
00599     };
00600 
00601     PG_RETURN_TIMESTAMP(result);
00602 }
00603 
00604 
00605 /*****************************************************************************
00606  *   USER I/O ROUTINES                                                       *
00607  *****************************************************************************/
00608 
00609 /*
00610  *      reltimein       - converts a reltime string in an internal format
00611  */
00612 Datum
00613 reltimein(PG_FUNCTION_ARGS)
00614 {
00615     char       *str = PG_GETARG_CSTRING(0);
00616     RelativeTime result;
00617     struct pg_tm tt,
00618                *tm = &tt;
00619     fsec_t      fsec;
00620     int         dtype;
00621     int         dterr;
00622     char       *field[MAXDATEFIELDS];
00623     int         nf,
00624                 ftype[MAXDATEFIELDS];
00625     char        workbuf[MAXDATELEN + 1];
00626 
00627     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
00628                           field, ftype, MAXDATEFIELDS, &nf);
00629     if (dterr == 0)
00630         dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
00631                                &dtype, tm, &fsec);
00632 
00633     /* if those functions think it's a bad format, try ISO8601 style */
00634     if (dterr == DTERR_BAD_FORMAT)
00635         dterr = DecodeISO8601Interval(str,
00636                                       &dtype, tm, &fsec);
00637 
00638     if (dterr != 0)
00639     {
00640         if (dterr == DTERR_FIELD_OVERFLOW)
00641             dterr = DTERR_INTERVAL_OVERFLOW;
00642         DateTimeParseError(dterr, str, "reltime");
00643     }
00644 
00645     switch (dtype)
00646     {
00647         case DTK_DELTA:
00648             result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec;
00649             result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY;
00650             break;
00651 
00652         default:
00653             elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
00654                  dtype, str);
00655             result = INVALID_RELTIME;
00656             break;
00657     }
00658 
00659     PG_RETURN_RELATIVETIME(result);
00660 }
00661 
00662 /*
00663  *      reltimeout      - converts the internal format to a reltime string
00664  */
00665 Datum
00666 reltimeout(PG_FUNCTION_ARGS)
00667 {
00668     RelativeTime time = PG_GETARG_RELATIVETIME(0);
00669     char       *result;
00670     struct pg_tm tt,
00671                *tm = &tt;
00672     char        buf[MAXDATELEN + 1];
00673 
00674     reltime2tm(time, tm);
00675     EncodeInterval(tm, 0, IntervalStyle, buf);
00676 
00677     result = pstrdup(buf);
00678     PG_RETURN_CSTRING(result);
00679 }
00680 
00681 /*
00682  *      reltimerecv         - converts external binary format to reltime
00683  */
00684 Datum
00685 reltimerecv(PG_FUNCTION_ARGS)
00686 {
00687     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00688 
00689     PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
00690 }
00691 
00692 /*
00693  *      reltimesend         - converts reltime to binary format
00694  */
00695 Datum
00696 reltimesend(PG_FUNCTION_ARGS)
00697 {
00698     RelativeTime time = PG_GETARG_RELATIVETIME(0);
00699     StringInfoData buf;
00700 
00701     pq_begintypsend(&buf);
00702     pq_sendint(&buf, time, sizeof(time));
00703     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00704 }
00705 
00706 
00707 static void
00708 reltime2tm(RelativeTime time, struct pg_tm * tm)
00709 {
00710     double      dtime = time;
00711 
00712     FMODULO(dtime, tm->tm_year, 31557600);
00713     FMODULO(dtime, tm->tm_mon, 2592000);
00714     FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
00715     FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR);
00716     FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE);
00717     FMODULO(dtime, tm->tm_sec, 1);
00718 }
00719 
00720 
00721 /*
00722  *      tintervalin     - converts an tinterval string to internal format
00723  */
00724 Datum
00725 tintervalin(PG_FUNCTION_ARGS)
00726 {
00727     char       *tintervalstr = PG_GETARG_CSTRING(0);
00728     TimeInterval tinterval;
00729     AbsoluteTime i_start,
00730                 i_end,
00731                 t1,
00732                 t2;
00733 
00734     parsetinterval(tintervalstr, &t1, &t2);
00735 
00736     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
00737 
00738     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
00739         tinterval->status = T_INTERVAL_INVAL;   /* undefined  */
00740     else
00741         tinterval->status = T_INTERVAL_VALID;
00742 
00743     i_start = ABSTIMEMIN(t1, t2);
00744     i_end = ABSTIMEMAX(t1, t2);
00745     tinterval->data[0] = i_start;
00746     tinterval->data[1] = i_end;
00747 
00748     PG_RETURN_TIMEINTERVAL(tinterval);
00749 }
00750 
00751 
00752 /*
00753  *      tintervalout    - converts an internal tinterval format to a string
00754  */
00755 Datum
00756 tintervalout(PG_FUNCTION_ARGS)
00757 {
00758     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
00759     char       *i_str,
00760                *p;
00761 
00762     i_str = (char *) palloc(T_INTERVAL_LEN);    /* ["..." "..."] */
00763     strcpy(i_str, "[\"");
00764     if (tinterval->status == T_INTERVAL_INVAL)
00765         strcat(i_str, INVALID_INTERVAL_STR);
00766     else
00767     {
00768         p = DatumGetCString(DirectFunctionCall1(abstimeout,
00769                                   AbsoluteTimeGetDatum(tinterval->data[0])));
00770         strcat(i_str, p);
00771         pfree(p);
00772         strcat(i_str, "\" \"");
00773         p = DatumGetCString(DirectFunctionCall1(abstimeout,
00774                                   AbsoluteTimeGetDatum(tinterval->data[1])));
00775         strcat(i_str, p);
00776         pfree(p);
00777     }
00778     strcat(i_str, "\"]");
00779     PG_RETURN_CSTRING(i_str);
00780 }
00781 
00782 /*
00783  *      tintervalrecv           - converts external binary format to tinterval
00784  */
00785 Datum
00786 tintervalrecv(PG_FUNCTION_ARGS)
00787 {
00788     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00789     TimeInterval tinterval;
00790     int32       status;
00791 
00792     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
00793 
00794     tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
00795     tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
00796     tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
00797 
00798     if (tinterval->data[0] == INVALID_ABSTIME ||
00799         tinterval->data[1] == INVALID_ABSTIME)
00800         status = T_INTERVAL_INVAL;      /* undefined  */
00801     else
00802         status = T_INTERVAL_VALID;
00803 
00804     if (status != tinterval->status)
00805         ereport(ERROR,
00806                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00807                  errmsg("invalid status in external \"tinterval\" value")));
00808 
00809     PG_RETURN_TIMEINTERVAL(tinterval);
00810 }
00811 
00812 /*
00813  *      tintervalsend           - converts tinterval to binary format
00814  */
00815 Datum
00816 tintervalsend(PG_FUNCTION_ARGS)
00817 {
00818     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
00819     StringInfoData buf;
00820 
00821     pq_begintypsend(&buf);
00822     pq_sendint(&buf, tinterval->status, sizeof(tinterval->status));
00823     pq_sendint(&buf, tinterval->data[0], sizeof(tinterval->data[0]));
00824     pq_sendint(&buf, tinterval->data[1], sizeof(tinterval->data[1]));
00825     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00826 }
00827 
00828 
00829 /*****************************************************************************
00830  *   PUBLIC ROUTINES                                                         *
00831  *****************************************************************************/
00832 
00833 Datum
00834 interval_reltime(PG_FUNCTION_ARGS)
00835 {
00836     Interval   *interval = PG_GETARG_INTERVAL_P(0);
00837     RelativeTime time;
00838     int         year,
00839                 month,
00840                 day;
00841     TimeOffset  span;
00842 
00843     year = interval->month / MONTHS_PER_YEAR;
00844     month = interval->month % MONTHS_PER_YEAR;
00845     day = interval->day;
00846 
00847 #ifdef HAVE_INT64_TIMESTAMP
00848     span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
00849              INT64CONST(1000000) * day) * INT64CONST(86400)) +
00850         interval->time;
00851     span /= USECS_PER_SEC;
00852 #else
00853     span = (DAYS_PER_YEAR * year + (double) DAYS_PER_MONTH * month + day) * SECS_PER_DAY + interval->time;
00854 #endif
00855 
00856     if (span < INT_MIN || span > INT_MAX)
00857         time = INVALID_RELTIME;
00858     else
00859         time = span;
00860 
00861     PG_RETURN_RELATIVETIME(time);
00862 }
00863 
00864 
00865 Datum
00866 reltime_interval(PG_FUNCTION_ARGS)
00867 {
00868     RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
00869     Interval   *result;
00870     int         year,
00871                 month,
00872                 day;
00873 
00874     result = (Interval *) palloc(sizeof(Interval));
00875 
00876     switch (reltime)
00877     {
00878         case INVALID_RELTIME:
00879             ereport(ERROR,
00880                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00881                   errmsg("cannot convert reltime \"invalid\" to interval")));
00882             result->time = 0;
00883             result->day = 0;
00884             result->month = 0;
00885             break;
00886 
00887         default:
00888 #ifdef HAVE_INT64_TIMESTAMP
00889             year = reltime / SECS_PER_YEAR;
00890             reltime -= year * SECS_PER_YEAR;
00891             month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY);
00892             reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY);
00893             day = reltime / SECS_PER_DAY;
00894             reltime -= day * SECS_PER_DAY;
00895 
00896             result->time = (reltime * USECS_PER_SEC);
00897 #else
00898             TMODULO(reltime, year, SECS_PER_YEAR);
00899             TMODULO(reltime, month, DAYS_PER_MONTH * SECS_PER_DAY);
00900             TMODULO(reltime, day, SECS_PER_DAY);
00901 
00902             result->time = reltime;
00903 #endif
00904             result->month = MONTHS_PER_YEAR * year + month;
00905             result->day = day;
00906             break;
00907     }
00908 
00909     PG_RETURN_INTERVAL_P(result);
00910 }
00911 
00912 
00913 /*
00914  *      mktinterval     - creates a time interval with endpoints t1 and t2
00915  */
00916 Datum
00917 mktinterval(PG_FUNCTION_ARGS)
00918 {
00919     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00920     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
00921     AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
00922     AbsoluteTime tend = ABSTIMEMAX(t1, t2);
00923     TimeInterval tinterval;
00924 
00925     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
00926 
00927     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
00928         tinterval->status = T_INTERVAL_INVAL;
00929 
00930     else
00931     {
00932         tinterval->status = T_INTERVAL_VALID;
00933         tinterval->data[0] = tstart;
00934         tinterval->data[1] = tend;
00935     }
00936 
00937     PG_RETURN_TIMEINTERVAL(tinterval);
00938 }
00939 
00940 /*
00941  *      timepl, timemi and abstimemi use the formula
00942  *              abstime + reltime = abstime
00943  *      so      abstime - reltime = abstime
00944  *      and     abstime - abstime = reltime
00945  */
00946 
00947 /*
00948  *      timepl          - returns the value of (abstime t1 + reltime t2)
00949  */
00950 Datum
00951 timepl(PG_FUNCTION_ARGS)
00952 {
00953     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00954     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
00955 
00956     if (AbsoluteTimeIsReal(t1) &&
00957         RelativeTimeIsValid(t2) &&
00958         ((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
00959          (t2 <= 0 && t1 > NOSTART_ABSTIME - t2)))       /* prevent overflow */
00960         PG_RETURN_ABSOLUTETIME(t1 + t2);
00961 
00962     PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
00963 }
00964 
00965 
00966 /*
00967  *      timemi          - returns the value of (abstime t1 - reltime t2)
00968  */
00969 Datum
00970 timemi(PG_FUNCTION_ARGS)
00971 {
00972     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
00973     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
00974 
00975     if (AbsoluteTimeIsReal(t1) &&
00976         RelativeTimeIsValid(t2) &&
00977         ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
00978          (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
00979         PG_RETURN_ABSOLUTETIME(t1 - t2);
00980 
00981     PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
00982 }
00983 
00984 
00985 /*
00986  *      intinterval     - returns true iff absolute date is in the tinterval
00987  */
00988 Datum
00989 intinterval(PG_FUNCTION_ARGS)
00990 {
00991     AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
00992     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1);
00993 
00994     if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
00995     {
00996         if (DatumGetBool(DirectFunctionCall2(abstimege,
00997                                              AbsoluteTimeGetDatum(t),
00998                                 AbsoluteTimeGetDatum(tinterval->data[0]))) &&
00999             DatumGetBool(DirectFunctionCall2(abstimele,
01000                                              AbsoluteTimeGetDatum(t),
01001                                   AbsoluteTimeGetDatum(tinterval->data[1]))))
01002             PG_RETURN_BOOL(true);
01003     }
01004     PG_RETURN_BOOL(false);
01005 }
01006 
01007 /*
01008  *      tintervalrel        - returns  relative time corresponding to tinterval
01009  */
01010 Datum
01011 tintervalrel(PG_FUNCTION_ARGS)
01012 {
01013     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
01014     AbsoluteTime t1 = tinterval->data[0];
01015     AbsoluteTime t2 = tinterval->data[1];
01016 
01017     if (tinterval->status != T_INTERVAL_VALID)
01018         PG_RETURN_RELATIVETIME(INVALID_RELTIME);
01019 
01020     if (AbsoluteTimeIsReal(t1) &&
01021         AbsoluteTimeIsReal(t2))
01022         PG_RETURN_RELATIVETIME(t2 - t1);
01023 
01024     PG_RETURN_RELATIVETIME(INVALID_RELTIME);
01025 }
01026 
01027 
01028 /*
01029  *      timenow         - returns  time "now", internal format
01030  *
01031  *      Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
01032  */
01033 Datum
01034 timenow(PG_FUNCTION_ARGS)
01035 {
01036     PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
01037 }
01038 
01039 /*
01040  * reltime comparison routines
01041  */
01042 static int
01043 reltime_cmp_internal(RelativeTime a, RelativeTime b)
01044 {
01045     /*
01046      * We consider all INVALIDs to be equal and larger than any non-INVALID.
01047      * This is somewhat arbitrary; the important thing is to have a consistent
01048      * sort order.
01049      */
01050     if (a == INVALID_RELTIME)
01051     {
01052         if (b == INVALID_RELTIME)
01053             return 0;           /* INVALID = INVALID */
01054         else
01055             return 1;           /* INVALID > non-INVALID */
01056     }
01057 
01058     if (b == INVALID_RELTIME)
01059         return -1;              /* non-INVALID < INVALID */
01060 
01061     if (a > b)
01062         return 1;
01063     else if (a == b)
01064         return 0;
01065     else
01066         return -1;
01067 }
01068 
01069 Datum
01070 reltimeeq(PG_FUNCTION_ARGS)
01071 {
01072     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01073     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01074 
01075     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
01076 }
01077 
01078 Datum
01079 reltimene(PG_FUNCTION_ARGS)
01080 {
01081     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01082     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01083 
01084     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
01085 }
01086 
01087 Datum
01088 reltimelt(PG_FUNCTION_ARGS)
01089 {
01090     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01091     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01092 
01093     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
01094 }
01095 
01096 Datum
01097 reltimegt(PG_FUNCTION_ARGS)
01098 {
01099     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01100     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01101 
01102     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
01103 }
01104 
01105 Datum
01106 reltimele(PG_FUNCTION_ARGS)
01107 {
01108     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01109     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01110 
01111     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
01112 }
01113 
01114 Datum
01115 reltimege(PG_FUNCTION_ARGS)
01116 {
01117     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01118     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01119 
01120     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
01121 }
01122 
01123 Datum
01124 btreltimecmp(PG_FUNCTION_ARGS)
01125 {
01126     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
01127     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
01128 
01129     PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
01130 }
01131 
01132 
01133 /*
01134  *      tintervalsame   - returns true iff tinterval i1 is same as tinterval i2
01135  *      Check begin and end time.
01136  */
01137 Datum
01138 tintervalsame(PG_FUNCTION_ARGS)
01139 {
01140     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01141     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01142 
01143     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
01144         PG_RETURN_BOOL(false);
01145 
01146     if (DatumGetBool(DirectFunctionCall2(abstimeeq,
01147                                          AbsoluteTimeGetDatum(i1->data[0]),
01148                                        AbsoluteTimeGetDatum(i2->data[0]))) &&
01149         DatumGetBool(DirectFunctionCall2(abstimeeq,
01150                                          AbsoluteTimeGetDatum(i1->data[1]),
01151                                          AbsoluteTimeGetDatum(i2->data[1]))))
01152         PG_RETURN_BOOL(true);
01153     PG_RETURN_BOOL(false);
01154 }
01155 
01156 /*
01157  * tinterval comparison routines
01158  *
01159  * Note: comparison is based only on the lengths of the tintervals, not on
01160  * endpoint values (as long as they're not INVALID).  This is pretty bogus,
01161  * but since it's only a legacy datatype, we're not going to change it.
01162  *
01163  * Some other bogus things that won't be changed for compatibility reasons:
01164  * 1. The interval length computations overflow at 2^31 seconds, causing
01165  * intervals longer than that to sort oddly compared to those shorter.
01166  * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
01167  * just ordinary integers.  Since this code doesn't handle them specially,
01168  * it's possible for [a b] to be considered longer than [c infinity] for
01169  * finite abstimes a, b, c.  In combination with the previous point, the
01170  * interval [-infinity infinity] is treated as being shorter than many finite
01171  * intervals :-(
01172  *
01173  * If tinterval is ever reimplemented atop timestamp, it'd be good to give
01174  * some consideration to avoiding these problems.
01175  */
01176 static int
01177 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
01178 {
01179     bool        a_invalid;
01180     bool        b_invalid;
01181     AbsoluteTime a_len;
01182     AbsoluteTime b_len;
01183 
01184     /*
01185      * We consider all INVALIDs to be equal and larger than any non-INVALID.
01186      * This is somewhat arbitrary; the important thing is to have a consistent
01187      * sort order.
01188      */
01189     a_invalid = a->status == T_INTERVAL_INVAL ||
01190         a->data[0] == INVALID_ABSTIME ||
01191         a->data[1] == INVALID_ABSTIME;
01192     b_invalid = b->status == T_INTERVAL_INVAL ||
01193         b->data[0] == INVALID_ABSTIME ||
01194         b->data[1] == INVALID_ABSTIME;
01195 
01196     if (a_invalid)
01197     {
01198         if (b_invalid)
01199             return 0;           /* INVALID = INVALID */
01200         else
01201             return 1;           /* INVALID > non-INVALID */
01202     }
01203 
01204     if (b_invalid)
01205         return -1;              /* non-INVALID < INVALID */
01206 
01207     a_len = a->data[1] - a->data[0];
01208     b_len = b->data[1] - b->data[0];
01209 
01210     if (a_len > b_len)
01211         return 1;
01212     else if (a_len == b_len)
01213         return 0;
01214     else
01215         return -1;
01216 }
01217 
01218 Datum
01219 tintervaleq(PG_FUNCTION_ARGS)
01220 {
01221     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01222     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01223 
01224     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
01225 }
01226 
01227 Datum
01228 tintervalne(PG_FUNCTION_ARGS)
01229 {
01230     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01231     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01232 
01233     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
01234 }
01235 
01236 Datum
01237 tintervallt(PG_FUNCTION_ARGS)
01238 {
01239     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01240     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01241 
01242     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
01243 }
01244 
01245 Datum
01246 tintervalle(PG_FUNCTION_ARGS)
01247 {
01248     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01249     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01250 
01251     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
01252 }
01253 
01254 Datum
01255 tintervalgt(PG_FUNCTION_ARGS)
01256 {
01257     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01258     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01259 
01260     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
01261 }
01262 
01263 Datum
01264 tintervalge(PG_FUNCTION_ARGS)
01265 {
01266     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01267     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01268 
01269     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
01270 }
01271 
01272 Datum
01273 bttintervalcmp(PG_FUNCTION_ARGS)
01274 {
01275     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01276     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01277 
01278     PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
01279 }
01280 
01281 
01282 /*
01283  *      tintervalleneq  - returns true iff length of tinterval i is equal to
01284  *                              reltime t
01285  *      tintervallenne  - returns true iff length of tinterval i is not equal
01286  *                              to reltime t
01287  *      tintervallenlt  - returns true iff length of tinterval i is less than
01288  *                              reltime t
01289  *      tintervallengt  - returns true iff length of tinterval i is greater
01290  *                              than reltime t
01291  *      tintervallenle  - returns true iff length of tinterval i is less or
01292  *                              equal than reltime t
01293  *      tintervallenge  - returns true iff length of tinterval i is greater or
01294  *                              equal than reltime t
01295  */
01296 Datum
01297 tintervalleneq(PG_FUNCTION_ARGS)
01298 {
01299     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01300     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01301     RelativeTime rt;
01302 
01303     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01304         PG_RETURN_BOOL(false);
01305     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01306                                                   TimeIntervalGetDatum(i)));
01307     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
01308 }
01309 
01310 Datum
01311 tintervallenne(PG_FUNCTION_ARGS)
01312 {
01313     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01314     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01315     RelativeTime rt;
01316 
01317     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01318         PG_RETURN_BOOL(false);
01319     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01320                                                   TimeIntervalGetDatum(i)));
01321     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
01322 }
01323 
01324 Datum
01325 tintervallenlt(PG_FUNCTION_ARGS)
01326 {
01327     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01328     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01329     RelativeTime rt;
01330 
01331     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01332         PG_RETURN_BOOL(false);
01333     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01334                                                   TimeIntervalGetDatum(i)));
01335     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
01336 }
01337 
01338 Datum
01339 tintervallengt(PG_FUNCTION_ARGS)
01340 {
01341     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01342     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01343     RelativeTime rt;
01344 
01345     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01346         PG_RETURN_BOOL(false);
01347     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01348                                                   TimeIntervalGetDatum(i)));
01349     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
01350 }
01351 
01352 Datum
01353 tintervallenle(PG_FUNCTION_ARGS)
01354 {
01355     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01356     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01357     RelativeTime rt;
01358 
01359     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01360         PG_RETURN_BOOL(false);
01361     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01362                                                   TimeIntervalGetDatum(i)));
01363     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
01364 }
01365 
01366 Datum
01367 tintervallenge(PG_FUNCTION_ARGS)
01368 {
01369     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01370     RelativeTime t = PG_GETARG_RELATIVETIME(1);
01371     RelativeTime rt;
01372 
01373     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
01374         PG_RETURN_BOOL(false);
01375     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
01376                                                   TimeIntervalGetDatum(i)));
01377     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
01378 }
01379 
01380 /*
01381  *      tintervalct     - returns true iff tinterval i1 contains tinterval i2
01382  */
01383 Datum
01384 tintervalct(PG_FUNCTION_ARGS)
01385 {
01386     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01387     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01388 
01389     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
01390         PG_RETURN_BOOL(false);
01391     if (DatumGetBool(DirectFunctionCall2(abstimele,
01392                                          AbsoluteTimeGetDatum(i1->data[0]),
01393                                        AbsoluteTimeGetDatum(i2->data[0]))) &&
01394         DatumGetBool(DirectFunctionCall2(abstimege,
01395                                          AbsoluteTimeGetDatum(i1->data[1]),
01396                                          AbsoluteTimeGetDatum(i2->data[1]))))
01397         PG_RETURN_BOOL(true);
01398     PG_RETURN_BOOL(false);
01399 }
01400 
01401 /*
01402  *      tintervalov     - returns true iff tinterval i1 (partially) overlaps i2
01403  */
01404 Datum
01405 tintervalov(PG_FUNCTION_ARGS)
01406 {
01407     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
01408     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
01409 
01410     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
01411         PG_RETURN_BOOL(false);
01412     if (DatumGetBool(DirectFunctionCall2(abstimelt,
01413                                          AbsoluteTimeGetDatum(i1->data[1]),
01414                                        AbsoluteTimeGetDatum(i2->data[0]))) ||
01415         DatumGetBool(DirectFunctionCall2(abstimegt,
01416                                          AbsoluteTimeGetDatum(i1->data[0]),
01417                                          AbsoluteTimeGetDatum(i2->data[1]))))
01418         PG_RETURN_BOOL(false);
01419     PG_RETURN_BOOL(true);
01420 }
01421 
01422 /*
01423  *      tintervalstart  - returns  the start of tinterval i
01424  */
01425 Datum
01426 tintervalstart(PG_FUNCTION_ARGS)
01427 {
01428     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01429 
01430     if (i->status == T_INTERVAL_INVAL)
01431         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
01432     PG_RETURN_ABSOLUTETIME(i->data[0]);
01433 }
01434 
01435 /*
01436  *      tintervalend        - returns  the end of tinterval i
01437  */
01438 Datum
01439 tintervalend(PG_FUNCTION_ARGS)
01440 {
01441     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
01442 
01443     if (i->status == T_INTERVAL_INVAL)
01444         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
01445     PG_RETURN_ABSOLUTETIME(i->data[1]);
01446 }
01447 
01448 
01449 /*****************************************************************************
01450  *   PRIVATE ROUTINES                                                        *
01451  *****************************************************************************/
01452 
01453 /*
01454  *      parsetinterval -- parse a tinterval string
01455  *
01456  *      output parameters:
01457  *              i_start, i_end: tinterval margins
01458  *
01459  *      Time interval:
01460  *      `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
01461  *
01462  *      OR  `Undefined Range'   (see also INVALID_INTERVAL_STR)
01463  *
01464  *      where <AbsTime> satisfies the syntax of absolute time.
01465  *
01466  *      e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
01467  */
01468 static void
01469 parsetinterval(char *i_string,
01470                AbsoluteTime *i_start,
01471                AbsoluteTime *i_end)
01472 {
01473     char       *p,
01474                *p1;
01475     char        c;
01476 
01477     p = i_string;
01478     /* skip leading blanks up to '[' */
01479     while ((c = *p) != '\0')
01480     {
01481         if (IsSpace(c))
01482             p++;
01483         else if (c != '[')
01484             goto bogus;         /* syntax error */
01485         else
01486             break;
01487     }
01488     if (c == '\0')
01489         goto bogus;             /* syntax error */
01490     p++;
01491     /* skip leading blanks up to '"' */
01492     while ((c = *p) != '\0')
01493     {
01494         if (IsSpace(c))
01495             p++;
01496         else if (c != '"')
01497             goto bogus;         /* syntax error */
01498         else
01499             break;
01500     }
01501     if (c == '\0')
01502         goto bogus;             /* syntax error */
01503     p++;
01504     if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
01505         goto bogus;             /* undefined range, handled like a syntax err. */
01506     /* search for the end of the first date and change it to a \0 */
01507     p1 = p;
01508     while ((c = *p1) != '\0')
01509     {
01510         if (c == '"')
01511             break;
01512         p1++;
01513     }
01514     if (c == '\0')
01515         goto bogus;             /* syntax error */
01516     *p1 = '\0';
01517     /* get the first date */
01518     *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
01519                                                         CStringGetDatum(p)));
01520     /* undo change to \0 */
01521     *p1 = c;
01522     p = ++p1;
01523     /* skip blanks up to '"', beginning of second date */
01524     while ((c = *p) != '\0')
01525     {
01526         if (IsSpace(c))
01527             p++;
01528         else if (c != '"')
01529             goto bogus;         /* syntax error */
01530         else
01531             break;
01532     }
01533     if (c == '\0')
01534         goto bogus;             /* syntax error */
01535     p++;
01536     /* search for the end of the second date and change it to a \0 */
01537     p1 = p;
01538     while ((c = *p1) != '\0')
01539     {
01540         if (c == '"')
01541             break;
01542         p1++;
01543     }
01544     if (c == '\0')
01545         goto bogus;             /* syntax error */
01546     *p1 = '\0';
01547     /* get the second date */
01548     *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
01549                                                       CStringGetDatum(p)));
01550     /* undo change to \0 */
01551     *p1 = c;
01552     p = ++p1;
01553     /* skip blanks up to ']' */
01554     while ((c = *p) != '\0')
01555     {
01556         if (IsSpace(c))
01557             p++;
01558         else if (c != ']')
01559             goto bogus;         /* syntax error */
01560         else
01561             break;
01562     }
01563     if (c == '\0')
01564         goto bogus;             /* syntax error */
01565     p++;
01566     c = *p;
01567     if (c != '\0')
01568         goto bogus;             /* syntax error */
01569 
01570     /* it seems to be a valid tinterval */
01571     return;
01572 
01573 bogus:
01574     ereport(ERROR,
01575             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
01576              errmsg("invalid input syntax for type tinterval: \"%s\"",
01577                     i_string)));
01578     *i_start = *i_end = INVALID_ABSTIME;        /* keep compiler quiet */
01579 }
01580 
01581 
01582 /*****************************************************************************
01583  *
01584  *****************************************************************************/
01585 
01586 /*
01587  * timeofday -
01588  *     returns the current time as a text. similar to timenow() but returns
01589  *     seconds with more precision (up to microsecs). (I need this to compare
01590  *     the Wisconsin benchmark with Illustra whose TimeNow() shows current
01591  *     time with precision up to microsecs.)              - ay 3/95
01592  */
01593 Datum
01594 timeofday(PG_FUNCTION_ARGS)
01595 {
01596     struct timeval tp;
01597     char        templ[128];
01598     char        buf[128];
01599     pg_time_t   tt;
01600 
01601     gettimeofday(&tp, NULL);
01602     tt = (pg_time_t) tp.tv_sec;
01603     pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
01604                 pg_localtime(&tt, session_timezone));
01605     snprintf(buf, sizeof(buf), templ, tp.tv_usec);
01606 
01607     PG_RETURN_TEXT_P(cstring_to_text(buf));
01608 }