LCOV - code coverage report
Current view: top level - src/backend/utils/adt - nabstime.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 445 601 74.0 %
Date: 2017-09-29 15:12:54 Functions: 49 66 74.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2017, PostgreSQL Global Development Group
       9             :  * Portions Copyright (c) 1994, Regents of the University of California
      10             :  *
      11             :  *
      12             :  * IDENTIFICATION
      13             :  *    src/backend/utils/adt/nabstime.c
      14             :  *
      15             :  *-------------------------------------------------------------------------
      16             :  */
      17             : #include "postgres.h"
      18             : 
      19             : #include <ctype.h>
      20             : #include <float.h>
      21             : #include <limits.h>
      22             : #include <math.h>
      23             : #include <time.h>
      24             : #include <sys/time.h>
      25             : 
      26             : #include "libpq/pqformat.h"
      27             : #include "miscadmin.h"
      28             : #include "utils/builtins.h"
      29             : #include "utils/datetime.h"
      30             : #include "utils/nabstime.h"
      31             : 
      32             : #define MIN_DAYNUM (-24856)     /* December 13, 1901 */
      33             : #define MAX_DAYNUM 24854        /* January 18, 2038 */
      34             : 
      35             : /*
      36             :  * Unix epoch is Jan  1 00:00:00 1970.
      37             :  * Postgres knows about times sixty-eight years on either side of that
      38             :  * for these 4-byte types.
      39             :  *
      40             :  * "tinterval" is two 4-byte fields.
      41             :  * Definitions for parsing tinterval.
      42             :  */
      43             : 
      44             : #define IsSpace(C)              ((C) == ' ')
      45             : 
      46             : #define T_INTERVAL_INVAL   0    /* data represents no valid tinterval */
      47             : #define T_INTERVAL_VALID   1    /* data represents a valid tinterval */
      48             : /*
      49             :  * ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
      50             :  * 0        1         2         3         4         5         6
      51             :  * 1234567890123456789012345678901234567890123456789012345678901234
      52             :  *
      53             :  * we allocate some extra -- timezones are usually 3 characters but
      54             :  * this is not in the POSIX standard...
      55             :  */
      56             : #define T_INTERVAL_LEN                  80
      57             : #define INVALID_INTERVAL_STR            "Undefined Range"
      58             : #define INVALID_INTERVAL_STR_LEN        (sizeof(INVALID_INTERVAL_STR)-1)
      59             : 
      60             : #define ABSTIMEMIN(t1, t2) \
      61             :     (DatumGetBool(DirectFunctionCall2(abstimele, \
      62             :                   AbsoluteTimeGetDatum(t1), \
      63             :                   AbsoluteTimeGetDatum(t2))) ? (t1) : (t2))
      64             : #define ABSTIMEMAX(t1, t2) \
      65             :     (DatumGetBool(DirectFunctionCall2(abstimelt, \
      66             :                   AbsoluteTimeGetDatum(t1), \
      67             :                   AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
      68             : 
      69             : 
      70             : /*
      71             :  * Function prototypes -- internal to this file only
      72             :  */
      73             : 
      74             : static AbsoluteTime tm2abstime(struct pg_tm *tm, int tz);
      75             : static void reltime2tm(RelativeTime time, struct pg_tm *tm);
      76             : static void parsetinterval(char *i_string,
      77             :                AbsoluteTime *i_start,
      78             :                AbsoluteTime *i_end);
      79             : 
      80             : 
      81             : /*
      82             :  * GetCurrentAbsoluteTime()
      83             :  *
      84             :  * Get the current system time (relative to Unix epoch).
      85             :  *
      86             :  * NB: this will overflow in 2038; it should be gone long before that.
      87             :  */
      88             : AbsoluteTime
      89           0 : GetCurrentAbsoluteTime(void)
      90             : {
      91             :     time_t      now;
      92             : 
      93           0 :     now = time(NULL);
      94           0 :     return (AbsoluteTime) now;
      95             : }
      96             : 
      97             : 
      98             : void
      99         231 : abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm *tm, char **tzn)
     100             : {
     101         231 :     pg_time_t   time = (pg_time_t) _time;
     102             :     struct pg_tm *tx;
     103             : 
     104         231 :     if (tzp != NULL)
     105         231 :         tx = pg_localtime(&time, session_timezone);
     106             :     else
     107           0 :         tx = pg_gmtime(&time);
     108             : 
     109         231 :     tm->tm_year = tx->tm_year + 1900;
     110         231 :     tm->tm_mon = tx->tm_mon + 1;
     111         231 :     tm->tm_mday = tx->tm_mday;
     112         231 :     tm->tm_hour = tx->tm_hour;
     113         231 :     tm->tm_min = tx->tm_min;
     114         231 :     tm->tm_sec = tx->tm_sec;
     115         231 :     tm->tm_isdst = tx->tm_isdst;
     116             : 
     117         231 :     tm->tm_gmtoff = tx->tm_gmtoff;
     118         231 :     tm->tm_zone = tx->tm_zone;
     119             : 
     120         231 :     if (tzp != NULL)
     121             :     {
     122         231 :         *tzp = -tm->tm_gmtoff;   /* tm_gmtoff is Sun/DEC-ism */
     123             : 
     124             :         /*
     125             :          * XXX FreeBSD man pages indicate that this should work - tgl 97/04/23
     126             :          */
     127         231 :         if (tzn != NULL)
     128             :         {
     129             :             /*
     130             :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
     131             :              * contains an error message, which doesn't fit in the buffer
     132             :              */
     133         227 :             StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
     134         227 :             if (strlen(tm->tm_zone) > MAXTZLEN)
     135           0 :                 ereport(WARNING,
     136             :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     137             :                          errmsg("invalid time zone name: \"%s\"",
     138             :                                 tm->tm_zone)));
     139             :         }
     140             :     }
     141             :     else
     142           0 :         tm->tm_isdst = -1;
     143         231 : }
     144             : 
     145             : 
     146             : /* tm2abstime()
     147             :  * Convert a tm structure to abstime.
     148             :  * Note that tm has full year (not 1900-based) and 1-based month.
     149             :  */
     150             : static AbsoluteTime
     151          53 : tm2abstime(struct pg_tm *tm, int tz)
     152             : {
     153             :     int         day;
     154             :     AbsoluteTime sec;
     155             : 
     156             :     /* validate, before going out of range on some members */
     157         105 :     if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
     158         156 :         tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
     159         156 :         tm->tm_mday < 1 || tm->tm_mday > 31 ||
     160         104 :         tm->tm_hour < 0 ||
     161         104 :         tm->tm_hour > HOURS_PER_DAY ||    /* test for > 24:00:00 */
     162         104 :         (tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
     163         156 :         tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
     164         104 :         tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
     165           1 :         return INVALID_ABSTIME;
     166             : 
     167          52 :     day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
     168             : 
     169             :     /* check for time out of range */
     170          52 :     if (day < MIN_DAYNUM || day > MAX_DAYNUM)
     171           0 :         return INVALID_ABSTIME;
     172             : 
     173             :     /* convert to seconds */
     174          52 :     sec = tm->tm_sec + tz + (tm->tm_min + (day * HOURS_PER_DAY + tm->tm_hour) * MINS_PER_HOUR) * SECS_PER_MINUTE;
     175             : 
     176             :     /*
     177             :      * check for overflow.  We need a little slop here because the H/M/S plus
     178             :      * TZ offset could add up to more than 1 day.
     179             :      */
     180          52 :     if ((day >= MAX_DAYNUM - 10 && sec < 0) ||
     181           0 :         (day <= MIN_DAYNUM + 10 && sec > 0))
     182           0 :         return INVALID_ABSTIME;
     183             : 
     184             :     /* check for reserved values (e.g. "current" on edge of usual range */
     185          52 :     if (!AbsoluteTimeIsReal(sec))
     186           0 :         return INVALID_ABSTIME;
     187             : 
     188          52 :     return sec;
     189             : }
     190             : 
     191             : 
     192             : /* abstimein()
     193             :  * Decode date/time string and return abstime.
     194             :  */
     195             : Datum
     196          56 : abstimein(PG_FUNCTION_ARGS)
     197             : {
     198          56 :     char       *str = PG_GETARG_CSTRING(0);
     199             :     AbsoluteTime result;
     200             :     fsec_t      fsec;
     201          56 :     int         tz = 0;
     202             :     struct pg_tm date,
     203          56 :                *tm = &date;
     204             :     int         dterr;
     205             :     char       *field[MAXDATEFIELDS];
     206             :     char        workbuf[MAXDATELEN + 1];
     207             :     int         dtype;
     208             :     int         nf,
     209             :                 ftype[MAXDATEFIELDS];
     210             : 
     211          56 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     212             :                           field, ftype, MAXDATEFIELDS, &nf);
     213          56 :     if (dterr == 0)
     214          56 :         dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
     215          56 :     if (dterr != 0)
     216           5 :         DateTimeParseError(dterr, str, "abstime");
     217             : 
     218          51 :     switch (dtype)
     219             :     {
     220             :         case DTK_DATE:
     221          37 :             result = tm2abstime(tm, tz);
     222          37 :             break;
     223             : 
     224             :         case DTK_EPOCH:
     225             : 
     226             :             /*
     227             :              * Don't bother retaining this as a reserved value, but instead
     228             :              * just set to the actual epoch time (1970-01-01)
     229             :              */
     230           7 :             result = 0;
     231           7 :             break;
     232             : 
     233             :         case DTK_LATE:
     234           4 :             result = NOEND_ABSTIME;
     235           4 :             break;
     236             : 
     237             :         case DTK_EARLY:
     238           3 :             result = NOSTART_ABSTIME;
     239           3 :             break;
     240             : 
     241             :         case DTK_INVALID:
     242           0 :             result = INVALID_ABSTIME;
     243           0 :             break;
     244             : 
     245             :         default:
     246           0 :             elog(ERROR, "unexpected dtype %d while parsing abstime \"%s\"",
     247             :                  dtype, str);
     248             :             result = INVALID_ABSTIME;
     249             :             break;
     250             :     };
     251             : 
     252          51 :     PG_RETURN_ABSOLUTETIME(result);
     253             : }
     254             : 
     255             : 
     256             : /* abstimeout()
     257             :  * Given an AbsoluteTime return the English text version of the date
     258             :  */
     259             : Datum
     260         264 : abstimeout(PG_FUNCTION_ARGS)
     261             : {
     262         264 :     AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
     263             :     char       *result;
     264             :     int         tz;
     265         264 :     double      fsec = 0;
     266             :     struct pg_tm tt,
     267         264 :                *tm = &tt;
     268             :     char        buf[MAXDATELEN + 1];
     269             :     char        zone[MAXDATELEN + 1],
     270         264 :                *tzn = zone;
     271             : 
     272         264 :     switch (time)
     273             :     {
     274             :             /*
     275             :              * Note that timestamp no longer supports 'invalid'. Retain
     276             :              * 'invalid' for abstime for now, but dump it someday.
     277             :              */
     278             :         case INVALID_ABSTIME:
     279           9 :             strcpy(buf, INVALID);
     280           9 :             break;
     281             :         case NOEND_ABSTIME:
     282          26 :             strcpy(buf, LATE);
     283          26 :             break;
     284             :         case NOSTART_ABSTIME:
     285          26 :             strcpy(buf, EARLY);
     286          26 :             break;
     287             :         default:
     288         203 :             abstime2tm(time, &tz, tm, &tzn);
     289         203 :             EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
     290         203 :             break;
     291             :     }
     292             : 
     293         264 :     result = pstrdup(buf);
     294         264 :     PG_RETURN_CSTRING(result);
     295             : }
     296             : 
     297             : /*
     298             :  *      abstimerecv         - converts external binary format to abstime
     299             :  */
     300             : Datum
     301           0 : abstimerecv(PG_FUNCTION_ARGS)
     302             : {
     303           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     304             : 
     305           0 :     PG_RETURN_ABSOLUTETIME((AbsoluteTime) pq_getmsgint(buf, sizeof(AbsoluteTime)));
     306             : }
     307             : 
     308             : /*
     309             :  *      abstimesend         - converts abstime to binary format
     310             :  */
     311             : Datum
     312           0 : abstimesend(PG_FUNCTION_ARGS)
     313             : {
     314           0 :     AbsoluteTime time = PG_GETARG_ABSOLUTETIME(0);
     315             :     StringInfoData buf;
     316             : 
     317           0 :     pq_begintypsend(&buf);
     318           0 :     pq_sendint(&buf, time, sizeof(time));
     319           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     320             : }
     321             : 
     322             : 
     323             : /* abstime_finite()
     324             :  */
     325             : Datum
     326          21 : abstime_finite(PG_FUNCTION_ARGS)
     327             : {
     328          21 :     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
     329             : 
     330          21 :     PG_RETURN_BOOL(abstime != INVALID_ABSTIME &&
     331             :                    abstime != NOSTART_ABSTIME &&
     332             :                    abstime != NOEND_ABSTIME);
     333             : }
     334             : 
     335             : 
     336             : /*
     337             :  * abstime comparison routines
     338             :  */
     339             : static int
     340         331 : abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
     341             : {
     342             :     /*
     343             :      * We consider all INVALIDs to be equal and larger than any non-INVALID.
     344             :      * This is somewhat arbitrary; the important thing is to have a consistent
     345             :      * sort order.
     346             :      */
     347         331 :     if (a == INVALID_ABSTIME)
     348             :     {
     349          33 :         if (b == INVALID_ABSTIME)
     350           0 :             return 0;           /* INVALID = INVALID */
     351             :         else
     352          33 :             return 1;           /* INVALID > non-INVALID */
     353             :     }
     354             : 
     355         298 :     if (b == INVALID_ABSTIME)
     356           2 :         return -1;              /* non-INVALID < INVALID */
     357             : 
     358         296 :     if (a > b)
     359         129 :         return 1;
     360         167 :     else if (a == b)
     361          27 :         return 0;
     362             :     else
     363         140 :         return -1;
     364             : }
     365             : 
     366             : Datum
     367           2 : abstimeeq(PG_FUNCTION_ARGS)
     368             : {
     369           2 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     370           2 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     371             : 
     372           2 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) == 0);
     373             : }
     374             : 
     375             : Datum
     376          11 : abstimene(PG_FUNCTION_ARGS)
     377             : {
     378          11 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     379          11 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     380             : 
     381          11 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) != 0);
     382             : }
     383             : 
     384             : Datum
     385         128 : abstimelt(PG_FUNCTION_ARGS)
     386             : {
     387         128 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     388         128 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     389             : 
     390         128 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) < 0);
     391             : }
     392             : 
     393             : Datum
     394          42 : abstimegt(PG_FUNCTION_ARGS)
     395             : {
     396          42 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     397          42 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     398             : 
     399          42 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) > 0);
     400             : }
     401             : 
     402             : Datum
     403          27 : abstimele(PG_FUNCTION_ARGS)
     404             : {
     405          27 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     406          27 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     407             : 
     408          27 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) <= 0);
     409             : }
     410             : 
     411             : Datum
     412          16 : abstimege(PG_FUNCTION_ARGS)
     413             : {
     414          16 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     415          16 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     416             : 
     417          16 :     PG_RETURN_BOOL(abstime_cmp_internal(t1, t2) >= 0);
     418             : }
     419             : 
     420             : Datum
     421         105 : btabstimecmp(PG_FUNCTION_ARGS)
     422             : {
     423         105 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     424         105 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     425             : 
     426         105 :     PG_RETURN_INT32(abstime_cmp_internal(t1, t2));
     427             : }
     428             : 
     429             : 
     430             : /* timestamp_abstime()
     431             :  * Convert timestamp to abstime.
     432             :  */
     433             : Datum
     434           2 : timestamp_abstime(PG_FUNCTION_ARGS)
     435             : {
     436           2 :     Timestamp   timestamp = PG_GETARG_TIMESTAMP(0);
     437             :     AbsoluteTime result;
     438             :     fsec_t      fsec;
     439             :     int         tz;
     440             :     struct pg_tm tt,
     441           2 :                *tm = &tt;
     442             : 
     443           2 :     if (TIMESTAMP_IS_NOBEGIN(timestamp))
     444           1 :         result = NOSTART_ABSTIME;
     445           1 :     else if (TIMESTAMP_IS_NOEND(timestamp))
     446           1 :         result = NOEND_ABSTIME;
     447           0 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
     448             :     {
     449           0 :         tz = DetermineTimeZoneOffset(tm, session_timezone);
     450           0 :         result = tm2abstime(tm, tz);
     451             :     }
     452             :     else
     453             :     {
     454           0 :         ereport(ERROR,
     455             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     456             :                  errmsg("timestamp out of range")));
     457             :         result = INVALID_ABSTIME;
     458             :     }
     459             : 
     460           2 :     PG_RETURN_ABSOLUTETIME(result);
     461             : }
     462             : 
     463             : /* abstime_timestamp()
     464             :  * Convert abstime to timestamp.
     465             :  */
     466             : Datum
     467           3 : abstime_timestamp(PG_FUNCTION_ARGS)
     468             : {
     469           3 :     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
     470             :     Timestamp   result;
     471             :     struct pg_tm tt,
     472           3 :                *tm = &tt;
     473             :     int         tz;
     474             :     char        zone[MAXDATELEN + 1],
     475           3 :                *tzn = zone;
     476             : 
     477           3 :     switch (abstime)
     478             :     {
     479             :         case INVALID_ABSTIME:
     480           1 :             ereport(ERROR,
     481             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     482             :                      errmsg("cannot convert abstime \"invalid\" to timestamp")));
     483             :             TIMESTAMP_NOBEGIN(result);
     484             :             break;
     485             : 
     486             :         case NOSTART_ABSTIME:
     487           1 :             TIMESTAMP_NOBEGIN(result);
     488           1 :             break;
     489             : 
     490             :         case NOEND_ABSTIME:
     491           1 :             TIMESTAMP_NOEND(result);
     492           1 :             break;
     493             : 
     494             :         default:
     495           0 :             abstime2tm(abstime, &tz, tm, &tzn);
     496           0 :             if (tm2timestamp(tm, 0, NULL, &result) != 0)
     497           0 :                 ereport(ERROR,
     498             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     499             :                          errmsg("timestamp out of range")));
     500           0 :             break;
     501             :     };
     502             : 
     503           2 :     PG_RETURN_TIMESTAMP(result);
     504             : }
     505             : 
     506             : 
     507             : /* timestamptz_abstime()
     508             :  * Convert timestamp with time zone to abstime.
     509             :  */
     510             : Datum
     511          16 : timestamptz_abstime(PG_FUNCTION_ARGS)
     512             : {
     513          16 :     TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
     514             :     AbsoluteTime result;
     515             :     fsec_t      fsec;
     516             :     struct pg_tm tt,
     517          16 :                *tm = &tt;
     518             : 
     519          16 :     if (TIMESTAMP_IS_NOBEGIN(timestamp))
     520           0 :         result = NOSTART_ABSTIME;
     521          16 :     else if (TIMESTAMP_IS_NOEND(timestamp))
     522           0 :         result = NOEND_ABSTIME;
     523          16 :     else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
     524          16 :         result = tm2abstime(tm, 0);
     525             :     else
     526             :     {
     527           0 :         ereport(ERROR,
     528             :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     529             :                  errmsg("timestamp out of range")));
     530             :         result = INVALID_ABSTIME;
     531             :     }
     532             : 
     533          16 :     PG_RETURN_ABSOLUTETIME(result);
     534             : }
     535             : 
     536             : /* abstime_timestamptz()
     537             :  * Convert abstime to timestamp with time zone.
     538             :  */
     539             : Datum
     540          24 : abstime_timestamptz(PG_FUNCTION_ARGS)
     541             : {
     542          24 :     AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
     543             :     TimestampTz result;
     544             :     struct pg_tm tt,
     545          24 :                *tm = &tt;
     546             :     int         tz;
     547             :     char        zone[MAXDATELEN + 1],
     548          24 :                *tzn = zone;
     549             : 
     550          24 :     switch (abstime)
     551             :     {
     552             :         case INVALID_ABSTIME:
     553           0 :             ereport(ERROR,
     554             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     555             :                      errmsg("cannot convert abstime \"invalid\" to timestamp")));
     556             :             TIMESTAMP_NOBEGIN(result);
     557             :             break;
     558             : 
     559             :         case NOSTART_ABSTIME:
     560           0 :             TIMESTAMP_NOBEGIN(result);
     561           0 :             break;
     562             : 
     563             :         case NOEND_ABSTIME:
     564           0 :             TIMESTAMP_NOEND(result);
     565           0 :             break;
     566             : 
     567             :         default:
     568          24 :             abstime2tm(abstime, &tz, tm, &tzn);
     569          24 :             if (tm2timestamp(tm, 0, &tz, &result) != 0)
     570           0 :                 ereport(ERROR,
     571             :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
     572             :                          errmsg("timestamp out of range")));
     573          24 :             break;
     574             :     };
     575             : 
     576          24 :     PG_RETURN_TIMESTAMP(result);
     577             : }
     578             : 
     579             : 
     580             : /*****************************************************************************
     581             :  *   USER I/O ROUTINES                                                       *
     582             :  *****************************************************************************/
     583             : 
     584             : /*
     585             :  *      reltimein       - converts a reltime string in an internal format
     586             :  */
     587             : Datum
     588          24 : reltimein(PG_FUNCTION_ARGS)
     589             : {
     590          24 :     char       *str = PG_GETARG_CSTRING(0);
     591             :     RelativeTime result;
     592             :     struct pg_tm tt,
     593          24 :                *tm = &tt;
     594             :     fsec_t      fsec;
     595             :     int         dtype;
     596             :     int         dterr;
     597             :     char       *field[MAXDATEFIELDS];
     598             :     int         nf,
     599             :                 ftype[MAXDATEFIELDS];
     600             :     char        workbuf[MAXDATELEN + 1];
     601             : 
     602          24 :     dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
     603             :                           field, ftype, MAXDATEFIELDS, &nf);
     604          24 :     if (dterr == 0)
     605          24 :         dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
     606             :                                &dtype, tm, &fsec);
     607             : 
     608             :     /* if those functions think it's a bad format, try ISO8601 style */
     609          24 :     if (dterr == DTERR_BAD_FORMAT)
     610           2 :         dterr = DecodeISO8601Interval(str,
     611             :                                       &dtype, tm, &fsec);
     612             : 
     613          24 :     if (dterr != 0)
     614             :     {
     615           2 :         if (dterr == DTERR_FIELD_OVERFLOW)
     616           0 :             dterr = DTERR_INTERVAL_OVERFLOW;
     617           2 :         DateTimeParseError(dterr, str, "reltime");
     618             :     }
     619             : 
     620          22 :     switch (dtype)
     621             :     {
     622             :         case DTK_DELTA:
     623          22 :             result = ((tm->tm_hour * MINS_PER_HOUR + tm->tm_min) * SECS_PER_MINUTE) + tm->tm_sec;
     624          22 :             result += tm->tm_year * SECS_PER_YEAR + ((tm->tm_mon * DAYS_PER_MONTH) + tm->tm_mday) * SECS_PER_DAY;
     625          22 :             break;
     626             : 
     627             :         default:
     628           0 :             elog(ERROR, "unexpected dtype %d while parsing reltime \"%s\"",
     629             :                  dtype, str);
     630             :             result = INVALID_RELTIME;
     631             :             break;
     632             :     }
     633             : 
     634          22 :     PG_RETURN_RELATIVETIME(result);
     635             : }
     636             : 
     637             : /*
     638             :  *      reltimeout      - converts the internal format to a reltime string
     639             :  */
     640             : Datum
     641          81 : reltimeout(PG_FUNCTION_ARGS)
     642             : {
     643          81 :     RelativeTime time = PG_GETARG_RELATIVETIME(0);
     644             :     char       *result;
     645             :     struct pg_tm tt,
     646          81 :                *tm = &tt;
     647             :     char        buf[MAXDATELEN + 1];
     648             : 
     649          81 :     reltime2tm(time, tm);
     650          81 :     EncodeInterval(tm, 0, IntervalStyle, buf);
     651             : 
     652          81 :     result = pstrdup(buf);
     653          81 :     PG_RETURN_CSTRING(result);
     654             : }
     655             : 
     656             : /*
     657             :  *      reltimerecv         - converts external binary format to reltime
     658             :  */
     659             : Datum
     660           0 : reltimerecv(PG_FUNCTION_ARGS)
     661             : {
     662           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     663             : 
     664           0 :     PG_RETURN_RELATIVETIME((RelativeTime) pq_getmsgint(buf, sizeof(RelativeTime)));
     665             : }
     666             : 
     667             : /*
     668             :  *      reltimesend         - converts reltime to binary format
     669             :  */
     670             : Datum
     671           0 : reltimesend(PG_FUNCTION_ARGS)
     672             : {
     673           0 :     RelativeTime time = PG_GETARG_RELATIVETIME(0);
     674             :     StringInfoData buf;
     675             : 
     676           0 :     pq_begintypsend(&buf);
     677           0 :     pq_sendint(&buf, time, sizeof(time));
     678           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     679             : }
     680             : 
     681             : 
     682             : static void
     683          81 : reltime2tm(RelativeTime time, struct pg_tm *tm)
     684             : {
     685          81 :     double      dtime = time;
     686             : 
     687          81 :     FMODULO(dtime, tm->tm_year, 31557600);
     688          81 :     FMODULO(dtime, tm->tm_mon, 2592000);
     689          81 :     FMODULO(dtime, tm->tm_mday, SECS_PER_DAY);
     690          81 :     FMODULO(dtime, tm->tm_hour, SECS_PER_HOUR);
     691          81 :     FMODULO(dtime, tm->tm_min, SECS_PER_MINUTE);
     692          81 :     FMODULO(dtime, tm->tm_sec, 1);
     693          81 : }
     694             : 
     695             : 
     696             : /*
     697             :  *      tintervalin     - converts an tinterval string to internal format
     698             :  */
     699             : Datum
     700          12 : tintervalin(PG_FUNCTION_ARGS)
     701             : {
     702          12 :     char       *tintervalstr = PG_GETARG_CSTRING(0);
     703             :     TimeInterval tinterval;
     704             :     AbsoluteTime i_start,
     705             :                 i_end,
     706             :                 t1,
     707             :                 t2;
     708             : 
     709          12 :     parsetinterval(tintervalstr, &t1, &t2);
     710             : 
     711          10 :     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
     712             : 
     713          10 :     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
     714           0 :         tinterval->status = T_INTERVAL_INVAL;    /* undefined  */
     715             :     else
     716          10 :         tinterval->status = T_INTERVAL_VALID;
     717             : 
     718          10 :     i_start = ABSTIMEMIN(t1, t2);
     719          10 :     i_end = ABSTIMEMAX(t1, t2);
     720          10 :     tinterval->data[0] = i_start;
     721          10 :     tinterval->data[1] = i_end;
     722             : 
     723          10 :     PG_RETURN_TIMEINTERVAL(tinterval);
     724             : }
     725             : 
     726             : 
     727             : /*
     728             :  *      tintervalout    - converts an internal tinterval format to a string
     729             :  */
     730             : Datum
     731          65 : tintervalout(PG_FUNCTION_ARGS)
     732             : {
     733          65 :     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
     734             :     char       *i_str,
     735             :                *p;
     736             : 
     737          65 :     i_str = (char *) palloc(T_INTERVAL_LEN);    /* ["..." "..."] */
     738          65 :     strcpy(i_str, "[\"");
     739          65 :     if (tinterval->status == T_INTERVAL_INVAL)
     740           0 :         strcat(i_str, INVALID_INTERVAL_STR);
     741             :     else
     742             :     {
     743          65 :         p = DatumGetCString(DirectFunctionCall1(abstimeout,
     744             :                                                 AbsoluteTimeGetDatum(tinterval->data[0])));
     745          65 :         strcat(i_str, p);
     746          65 :         pfree(p);
     747          65 :         strcat(i_str, "\" \"");
     748          65 :         p = DatumGetCString(DirectFunctionCall1(abstimeout,
     749             :                                                 AbsoluteTimeGetDatum(tinterval->data[1])));
     750          65 :         strcat(i_str, p);
     751          65 :         pfree(p);
     752             :     }
     753          65 :     strcat(i_str, "\"]");
     754          65 :     PG_RETURN_CSTRING(i_str);
     755             : }
     756             : 
     757             : /*
     758             :  *      tintervalrecv           - converts external binary format to tinterval
     759             :  */
     760             : Datum
     761           0 : tintervalrecv(PG_FUNCTION_ARGS)
     762             : {
     763           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     764             :     TimeInterval tinterval;
     765             :     int32       status;
     766             : 
     767           0 :     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
     768             : 
     769           0 :     tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
     770           0 :     tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
     771           0 :     tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
     772             : 
     773           0 :     if (tinterval->data[0] == INVALID_ABSTIME ||
     774           0 :         tinterval->data[1] == INVALID_ABSTIME)
     775           0 :         status = T_INTERVAL_INVAL;  /* undefined  */
     776             :     else
     777           0 :         status = T_INTERVAL_VALID;
     778             : 
     779           0 :     if (status != tinterval->status)
     780           0 :         ereport(ERROR,
     781             :                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
     782             :                  errmsg("invalid status in external \"tinterval\" value")));
     783             : 
     784           0 :     PG_RETURN_TIMEINTERVAL(tinterval);
     785             : }
     786             : 
     787             : /*
     788             :  *      tintervalsend           - converts tinterval to binary format
     789             :  */
     790             : Datum
     791           0 : tintervalsend(PG_FUNCTION_ARGS)
     792             : {
     793           0 :     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
     794             :     StringInfoData buf;
     795             : 
     796           0 :     pq_begintypsend(&buf);
     797           0 :     pq_sendint(&buf, tinterval->status, sizeof(tinterval->status));
     798           0 :     pq_sendint(&buf, tinterval->data[0], sizeof(tinterval->data[0]));
     799           0 :     pq_sendint(&buf, tinterval->data[1], sizeof(tinterval->data[1]));
     800           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     801             : }
     802             : 
     803             : 
     804             : /*****************************************************************************
     805             :  *   PUBLIC ROUTINES                                                         *
     806             :  *****************************************************************************/
     807             : 
     808             : Datum
     809          10 : interval_reltime(PG_FUNCTION_ARGS)
     810             : {
     811          10 :     Interval   *interval = PG_GETARG_INTERVAL_P(0);
     812             :     RelativeTime time;
     813             :     int         year,
     814             :                 month,
     815             :                 day;
     816             :     TimeOffset  span;
     817             : 
     818          10 :     year = interval->month / MONTHS_PER_YEAR;
     819          10 :     month = interval->month % MONTHS_PER_YEAR;
     820          10 :     day = interval->day;
     821             : 
     822          10 :     span = ((INT64CONST(365250000) * year + INT64CONST(30000000) * month +
     823          10 :              INT64CONST(1000000) * day) * INT64CONST(86400)) +
     824          10 :         interval->time;
     825          10 :     span /= USECS_PER_SEC;
     826             : 
     827          10 :     if (span < INT_MIN || span > INT_MAX)
     828           0 :         time = INVALID_RELTIME;
     829             :     else
     830          10 :         time = span;
     831             : 
     832          10 :     PG_RETURN_RELATIVETIME(time);
     833             : }
     834             : 
     835             : 
     836             : Datum
     837           6 : reltime_interval(PG_FUNCTION_ARGS)
     838             : {
     839           6 :     RelativeTime reltime = PG_GETARG_RELATIVETIME(0);
     840             :     Interval   *result;
     841             :     int         year,
     842             :                 month,
     843             :                 day;
     844             : 
     845           6 :     result = (Interval *) palloc(sizeof(Interval));
     846             : 
     847           6 :     switch (reltime)
     848             :     {
     849             :         case INVALID_RELTIME:
     850           0 :             ereport(ERROR,
     851             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     852             :                      errmsg("cannot convert reltime \"invalid\" to interval")));
     853             :             result->time = 0;
     854             :             result->day = 0;
     855             :             result->month = 0;
     856             :             break;
     857             : 
     858             :         default:
     859           6 :             year = reltime / SECS_PER_YEAR;
     860           6 :             reltime -= year * SECS_PER_YEAR;
     861           6 :             month = reltime / (DAYS_PER_MONTH * SECS_PER_DAY);
     862           6 :             reltime -= month * (DAYS_PER_MONTH * SECS_PER_DAY);
     863           6 :             day = reltime / SECS_PER_DAY;
     864           6 :             reltime -= day * SECS_PER_DAY;
     865             : 
     866           6 :             result->time = (reltime * USECS_PER_SEC);
     867           6 :             result->month = MONTHS_PER_YEAR * year + month;
     868           6 :             result->day = day;
     869           6 :             break;
     870             :     }
     871             : 
     872           6 :     PG_RETURN_INTERVAL_P(result);
     873             : }
     874             : 
     875             : 
     876             : /*
     877             :  *      mktinterval     - creates a time interval with endpoints t1 and t2
     878             :  */
     879             : Datum
     880           1 : mktinterval(PG_FUNCTION_ARGS)
     881             : {
     882           1 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     883           1 :     AbsoluteTime t2 = PG_GETARG_ABSOLUTETIME(1);
     884           1 :     AbsoluteTime tstart = ABSTIMEMIN(t1, t2);
     885           1 :     AbsoluteTime tend = ABSTIMEMAX(t1, t2);
     886             :     TimeInterval tinterval;
     887             : 
     888           1 :     tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
     889             : 
     890           1 :     if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
     891           0 :         tinterval->status = T_INTERVAL_INVAL;
     892             : 
     893             :     else
     894             :     {
     895           1 :         tinterval->status = T_INTERVAL_VALID;
     896           1 :         tinterval->data[0] = tstart;
     897           1 :         tinterval->data[1] = tend;
     898             :     }
     899             : 
     900           1 :     PG_RETURN_TIMEINTERVAL(tinterval);
     901             : }
     902             : 
     903             : /*
     904             :  *      timepl, timemi and abstimemi use the formula
     905             :  *              abstime + reltime = abstime
     906             :  *      so      abstime - reltime = abstime
     907             :  *      and     abstime - abstime = reltime
     908             :  */
     909             : 
     910             : /*
     911             :  *      timepl          - returns the value of (abstime t1 + reltime t2)
     912             :  */
     913             : Datum
     914          56 : timepl(PG_FUNCTION_ARGS)
     915             : {
     916          56 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     917          56 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
     918             : 
     919          56 :     if (AbsoluteTimeIsReal(t1) &&
     920          32 :         RelativeTimeIsValid(t2) &&
     921          24 :         ((t2 > 0 && t1 < NOEND_ABSTIME - t2) ||
     922           8 :          (t2 <= 0 && t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
     923          32 :         PG_RETURN_ABSOLUTETIME(t1 + t2);
     924             : 
     925          24 :     PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
     926             : }
     927             : 
     928             : 
     929             : /*
     930             :  *      timemi          - returns the value of (abstime t1 - reltime t2)
     931             :  */
     932             : Datum
     933          14 : timemi(PG_FUNCTION_ARGS)
     934             : {
     935          14 :     AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
     936          14 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
     937             : 
     938          14 :     if (AbsoluteTimeIsReal(t1) &&
     939           8 :         RelativeTimeIsValid(t2) &&
     940           4 :         ((t2 > 0 && t1 > NOSTART_ABSTIME + t2) ||
     941           4 :          (t2 <= 0 && t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
     942           8 :         PG_RETURN_ABSOLUTETIME(t1 - t2);
     943             : 
     944           6 :     PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
     945             : }
     946             : 
     947             : 
     948             : /*
     949             :  *      intinterval     - returns true iff absolute date is in the tinterval
     950             :  */
     951             : Datum
     952           7 : intinterval(PG_FUNCTION_ARGS)
     953             : {
     954           7 :     AbsoluteTime t = PG_GETARG_ABSOLUTETIME(0);
     955           7 :     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(1);
     956             : 
     957           7 :     if (tinterval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
     958             :     {
     959           6 :         if (DatumGetBool(DirectFunctionCall2(abstimege,
     960             :                                              AbsoluteTimeGetDatum(t),
     961           4 :                                              AbsoluteTimeGetDatum(tinterval->data[0]))) &&
     962           4 :             DatumGetBool(DirectFunctionCall2(abstimele,
     963             :                                              AbsoluteTimeGetDatum(t),
     964             :                                              AbsoluteTimeGetDatum(tinterval->data[1]))))
     965           3 :             PG_RETURN_BOOL(true);
     966             :     }
     967           4 :     PG_RETURN_BOOL(false);
     968             : }
     969             : 
     970             : /*
     971             :  *      tintervalrel        - returns  relative time corresponding to tinterval
     972             :  */
     973             : Datum
     974          30 : tintervalrel(PG_FUNCTION_ARGS)
     975             : {
     976          30 :     TimeInterval tinterval = PG_GETARG_TIMEINTERVAL(0);
     977          30 :     AbsoluteTime t1 = tinterval->data[0];
     978          30 :     AbsoluteTime t2 = tinterval->data[1];
     979             : 
     980          30 :     if (tinterval->status != T_INTERVAL_VALID)
     981           0 :         PG_RETURN_RELATIVETIME(INVALID_RELTIME);
     982             : 
     983          54 :     if (AbsoluteTimeIsReal(t1) &&
     984          24 :         AbsoluteTimeIsReal(t2))
     985          24 :         PG_RETURN_RELATIVETIME(t2 - t1);
     986             : 
     987           6 :     PG_RETURN_RELATIVETIME(INVALID_RELTIME);
     988             : }
     989             : 
     990             : 
     991             : /*
     992             :  *      timenow         - returns  time "now", internal format
     993             :  *
     994             :  *      Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
     995             :  */
     996             : Datum
     997           0 : timenow(PG_FUNCTION_ARGS)
     998             : {
     999           0 :     PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
    1000             : }
    1001             : 
    1002             : /*
    1003             :  * reltime comparison routines
    1004             :  */
    1005             : static int
    1006         163 : reltime_cmp_internal(RelativeTime a, RelativeTime b)
    1007             : {
    1008             :     /*
    1009             :      * We consider all INVALIDs to be equal and larger than any non-INVALID.
    1010             :      * This is somewhat arbitrary; the important thing is to have a consistent
    1011             :      * sort order.
    1012             :      */
    1013         163 :     if (a == INVALID_RELTIME)
    1014             :     {
    1015           0 :         if (b == INVALID_RELTIME)
    1016           0 :             return 0;           /* INVALID = INVALID */
    1017             :         else
    1018           0 :             return 1;           /* INVALID > non-INVALID */
    1019             :     }
    1020             : 
    1021         163 :     if (b == INVALID_RELTIME)
    1022           0 :         return -1;              /* non-INVALID < INVALID */
    1023             : 
    1024         163 :     if (a > b)
    1025          66 :         return 1;
    1026          97 :     else if (a == b)
    1027          31 :         return 0;
    1028             :     else
    1029          66 :         return -1;
    1030             : }
    1031             : 
    1032             : Datum
    1033           6 : reltimeeq(PG_FUNCTION_ARGS)
    1034             : {
    1035           6 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1036           6 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1037             : 
    1038           6 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
    1039             : }
    1040             : 
    1041             : Datum
    1042           6 : reltimene(PG_FUNCTION_ARGS)
    1043             : {
    1044           6 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1045           6 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1046             : 
    1047           6 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
    1048             : }
    1049             : 
    1050             : Datum
    1051           6 : reltimelt(PG_FUNCTION_ARGS)
    1052             : {
    1053           6 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1054           6 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1055             : 
    1056           6 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
    1057             : }
    1058             : 
    1059             : Datum
    1060          42 : reltimegt(PG_FUNCTION_ARGS)
    1061             : {
    1062          42 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1063          42 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1064             : 
    1065          42 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
    1066             : }
    1067             : 
    1068             : Datum
    1069           6 : reltimele(PG_FUNCTION_ARGS)
    1070             : {
    1071           6 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1072           6 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1073             : 
    1074           6 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
    1075             : }
    1076             : 
    1077             : Datum
    1078           6 : reltimege(PG_FUNCTION_ARGS)
    1079             : {
    1080           6 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1081           6 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1082             : 
    1083           6 :     PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
    1084             : }
    1085             : 
    1086             : Datum
    1087          91 : btreltimecmp(PG_FUNCTION_ARGS)
    1088             : {
    1089          91 :     RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
    1090          91 :     RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
    1091             : 
    1092          91 :     PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
    1093             : }
    1094             : 
    1095             : 
    1096             : /*
    1097             :  *      tintervalsame   - returns true iff tinterval i1 is same as tinterval i2
    1098             :  *      Check begin and end time.
    1099             :  */
    1100             : Datum
    1101           0 : tintervalsame(PG_FUNCTION_ARGS)
    1102             : {
    1103           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1104           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1105             : 
    1106           0 :     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
    1107           0 :         PG_RETURN_BOOL(false);
    1108             : 
    1109           0 :     if (DatumGetBool(DirectFunctionCall2(abstimeeq,
    1110             :                                          AbsoluteTimeGetDatum(i1->data[0]),
    1111           0 :                                          AbsoluteTimeGetDatum(i2->data[0]))) &&
    1112           0 :         DatumGetBool(DirectFunctionCall2(abstimeeq,
    1113             :                                          AbsoluteTimeGetDatum(i1->data[1]),
    1114             :                                          AbsoluteTimeGetDatum(i2->data[1]))))
    1115           0 :         PG_RETURN_BOOL(true);
    1116           0 :     PG_RETURN_BOOL(false);
    1117             : }
    1118             : 
    1119             : /*
    1120             :  * tinterval comparison routines
    1121             :  *
    1122             :  * Note: comparison is based only on the lengths of the tintervals, not on
    1123             :  * endpoint values (as long as they're not INVALID).  This is pretty bogus,
    1124             :  * but since it's only a legacy datatype, we're not going to change it.
    1125             :  *
    1126             :  * Some other bogus things that won't be changed for compatibility reasons:
    1127             :  * 1. The interval length computations overflow at 2^31 seconds, causing
    1128             :  * intervals longer than that to sort oddly compared to those shorter.
    1129             :  * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
    1130             :  * just ordinary integers.  Since this code doesn't handle them specially,
    1131             :  * it's possible for [a b] to be considered longer than [c infinity] for
    1132             :  * finite abstimes a, b, c.  In combination with the previous point, the
    1133             :  * interval [-infinity infinity] is treated as being shorter than many finite
    1134             :  * intervals :-(
    1135             :  *
    1136             :  * If tinterval is ever reimplemented atop timestamp, it'd be good to give
    1137             :  * some consideration to avoiding these problems.
    1138             :  */
    1139             : static int
    1140         108 : tinterval_cmp_internal(TimeInterval a, TimeInterval b)
    1141             : {
    1142             :     bool        a_invalid;
    1143             :     bool        b_invalid;
    1144             :     AbsoluteTime a_len;
    1145             :     AbsoluteTime b_len;
    1146             : 
    1147             :     /*
    1148             :      * We consider all INVALIDs to be equal and larger than any non-INVALID.
    1149             :      * This is somewhat arbitrary; the important thing is to have a consistent
    1150             :      * sort order.
    1151             :      */
    1152         324 :     a_invalid = a->status == T_INTERVAL_INVAL ||
    1153         216 :         a->data[0] == INVALID_ABSTIME ||
    1154         108 :         a->data[1] == INVALID_ABSTIME;
    1155         324 :     b_invalid = b->status == T_INTERVAL_INVAL ||
    1156         216 :         b->data[0] == INVALID_ABSTIME ||
    1157         108 :         b->data[1] == INVALID_ABSTIME;
    1158             : 
    1159         108 :     if (a_invalid)
    1160             :     {
    1161           0 :         if (b_invalid)
    1162           0 :             return 0;           /* INVALID = INVALID */
    1163             :         else
    1164           0 :             return 1;           /* INVALID > non-INVALID */
    1165             :     }
    1166             : 
    1167         108 :     if (b_invalid)
    1168           0 :         return -1;              /* non-INVALID < INVALID */
    1169             : 
    1170         108 :     a_len = a->data[1] - a->data[0];
    1171         108 :     b_len = b->data[1] - b->data[0];
    1172             : 
    1173         108 :     if (a_len > b_len)
    1174          46 :         return 1;
    1175          62 :     else if (a_len == b_len)
    1176          23 :         return 0;
    1177             :     else
    1178          39 :         return -1;
    1179             : }
    1180             : 
    1181             : Datum
    1182           0 : tintervaleq(PG_FUNCTION_ARGS)
    1183             : {
    1184           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1185           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1186             : 
    1187           0 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
    1188             : }
    1189             : 
    1190             : Datum
    1191          19 : tintervalne(PG_FUNCTION_ARGS)
    1192             : {
    1193          19 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1194          19 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1195             : 
    1196          19 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
    1197             : }
    1198             : 
    1199             : Datum
    1200           0 : tintervallt(PG_FUNCTION_ARGS)
    1201             : {
    1202           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1203           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1204             : 
    1205           0 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
    1206             : }
    1207             : 
    1208             : Datum
    1209           0 : tintervalle(PG_FUNCTION_ARGS)
    1210             : {
    1211           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1212           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1213             : 
    1214           0 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
    1215             : }
    1216             : 
    1217             : Datum
    1218           0 : tintervalgt(PG_FUNCTION_ARGS)
    1219             : {
    1220           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1221           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1222             : 
    1223           0 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
    1224             : }
    1225             : 
    1226             : Datum
    1227           0 : tintervalge(PG_FUNCTION_ARGS)
    1228             : {
    1229           0 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1230           0 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1231             : 
    1232           0 :     PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
    1233             : }
    1234             : 
    1235             : Datum
    1236          89 : bttintervalcmp(PG_FUNCTION_ARGS)
    1237             : {
    1238          89 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1239          89 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1240             : 
    1241          89 :     PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
    1242             : }
    1243             : 
    1244             : 
    1245             : /*
    1246             :  *      tintervalleneq  - returns true iff length of tinterval i is equal to
    1247             :  *                              reltime t
    1248             :  *      tintervallenne  - returns true iff length of tinterval i is not equal
    1249             :  *                              to reltime t
    1250             :  *      tintervallenlt  - returns true iff length of tinterval i is less than
    1251             :  *                              reltime t
    1252             :  *      tintervallengt  - returns true iff length of tinterval i is greater
    1253             :  *                              than reltime t
    1254             :  *      tintervallenle  - returns true iff length of tinterval i is less or
    1255             :  *                              equal than reltime t
    1256             :  *      tintervallenge  - returns true iff length of tinterval i is greater or
    1257             :  *                              equal than reltime t
    1258             :  */
    1259             : Datum
    1260           5 : tintervalleneq(PG_FUNCTION_ARGS)
    1261             : {
    1262           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1263           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1264             :     RelativeTime rt;
    1265             : 
    1266           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1267           0 :         PG_RETURN_BOOL(false);
    1268           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1269             :                                                   TimeIntervalGetDatum(i)));
    1270           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt == t);
    1271             : }
    1272             : 
    1273             : Datum
    1274           5 : tintervallenne(PG_FUNCTION_ARGS)
    1275             : {
    1276           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1277           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1278             :     RelativeTime rt;
    1279             : 
    1280           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1281           0 :         PG_RETURN_BOOL(false);
    1282           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1283             :                                                   TimeIntervalGetDatum(i)));
    1284           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt != t);
    1285             : }
    1286             : 
    1287             : Datum
    1288           5 : tintervallenlt(PG_FUNCTION_ARGS)
    1289             : {
    1290           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1291           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1292             :     RelativeTime rt;
    1293             : 
    1294           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1295           0 :         PG_RETURN_BOOL(false);
    1296           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1297             :                                                   TimeIntervalGetDatum(i)));
    1298           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt < t);
    1299             : }
    1300             : 
    1301             : Datum
    1302           5 : tintervallengt(PG_FUNCTION_ARGS)
    1303             : {
    1304           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1305           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1306             :     RelativeTime rt;
    1307             : 
    1308           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1309           0 :         PG_RETURN_BOOL(false);
    1310           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1311             :                                                   TimeIntervalGetDatum(i)));
    1312           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt > t);
    1313             : }
    1314             : 
    1315             : Datum
    1316           5 : tintervallenle(PG_FUNCTION_ARGS)
    1317             : {
    1318           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1319           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1320             :     RelativeTime rt;
    1321             : 
    1322           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1323           0 :         PG_RETURN_BOOL(false);
    1324           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1325             :                                                   TimeIntervalGetDatum(i)));
    1326           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt <= t);
    1327             : }
    1328             : 
    1329             : Datum
    1330           5 : tintervallenge(PG_FUNCTION_ARGS)
    1331             : {
    1332           5 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1333           5 :     RelativeTime t = PG_GETARG_RELATIVETIME(1);
    1334             :     RelativeTime rt;
    1335             : 
    1336           5 :     if (i->status == T_INTERVAL_INVAL || t == INVALID_RELTIME)
    1337           0 :         PG_RETURN_BOOL(false);
    1338           5 :     rt = DatumGetRelativeTime(DirectFunctionCall1(tintervalrel,
    1339             :                                                   TimeIntervalGetDatum(i)));
    1340           5 :     PG_RETURN_BOOL(rt != INVALID_RELTIME && rt >= t);
    1341             : }
    1342             : 
    1343             : /*
    1344             :  *      tintervalct     - returns true iff tinterval i1 contains tinterval i2
    1345             :  */
    1346             : Datum
    1347           5 : tintervalct(PG_FUNCTION_ARGS)
    1348             : {
    1349           5 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1350           5 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1351             : 
    1352           5 :     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
    1353           0 :         PG_RETURN_BOOL(false);
    1354           5 :     if (DatumGetBool(DirectFunctionCall2(abstimele,
    1355             :                                          AbsoluteTimeGetDatum(i1->data[0]),
    1356           3 :                                          AbsoluteTimeGetDatum(i2->data[0]))) &&
    1357           3 :         DatumGetBool(DirectFunctionCall2(abstimege,
    1358             :                                          AbsoluteTimeGetDatum(i1->data[1]),
    1359             :                                          AbsoluteTimeGetDatum(i2->data[1]))))
    1360           2 :         PG_RETURN_BOOL(true);
    1361           3 :     PG_RETURN_BOOL(false);
    1362             : }
    1363             : 
    1364             : /*
    1365             :  *      tintervalov     - returns true iff tinterval i1 (partially) overlaps i2
    1366             :  */
    1367             : Datum
    1368          40 : tintervalov(PG_FUNCTION_ARGS)
    1369             : {
    1370          40 :     TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
    1371          40 :     TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
    1372             : 
    1373          40 :     if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
    1374           0 :         PG_RETURN_BOOL(false);
    1375          40 :     if (DatumGetBool(DirectFunctionCall2(abstimelt,
    1376             :                                          AbsoluteTimeGetDatum(i1->data[1]),
    1377          35 :                                          AbsoluteTimeGetDatum(i2->data[0]))) ||
    1378          35 :         DatumGetBool(DirectFunctionCall2(abstimegt,
    1379             :                                          AbsoluteTimeGetDatum(i1->data[0]),
    1380             :                                          AbsoluteTimeGetDatum(i2->data[1]))))
    1381          10 :         PG_RETURN_BOOL(false);
    1382          30 :     PG_RETURN_BOOL(true);
    1383             : }
    1384             : 
    1385             : /*
    1386             :  *      tintervalstart  - returns  the start of tinterval i
    1387             :  */
    1388             : Datum
    1389           0 : tintervalstart(PG_FUNCTION_ARGS)
    1390             : {
    1391           0 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1392             : 
    1393           0 :     if (i->status == T_INTERVAL_INVAL)
    1394           0 :         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
    1395           0 :     PG_RETURN_ABSOLUTETIME(i->data[0]);
    1396             : }
    1397             : 
    1398             : /*
    1399             :  *      tintervalend        - returns  the end of tinterval i
    1400             :  */
    1401             : Datum
    1402           0 : tintervalend(PG_FUNCTION_ARGS)
    1403             : {
    1404           0 :     TimeInterval i = PG_GETARG_TIMEINTERVAL(0);
    1405             : 
    1406           0 :     if (i->status == T_INTERVAL_INVAL)
    1407           0 :         PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
    1408           0 :     PG_RETURN_ABSOLUTETIME(i->data[1]);
    1409             : }
    1410             : 
    1411             : 
    1412             : /*****************************************************************************
    1413             :  *   PRIVATE ROUTINES                                                        *
    1414             :  *****************************************************************************/
    1415             : 
    1416             : /*
    1417             :  *      parsetinterval -- parse a tinterval string
    1418             :  *
    1419             :  *      output parameters:
    1420             :  *              i_start, i_end: tinterval margins
    1421             :  *
    1422             :  *      Time interval:
    1423             :  *      `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
    1424             :  *
    1425             :  *      OR  `Undefined Range'   (see also INVALID_INTERVAL_STR)
    1426             :  *
    1427             :  *      where <AbsTime> satisfies the syntax of absolute time.
    1428             :  *
    1429             :  *      e.g.  [  '  Jan 18 1902'   'Jan 1 00:00:00 1970']
    1430             :  */
    1431             : static void
    1432          12 : parsetinterval(char *i_string,
    1433             :                AbsoluteTime *i_start,
    1434             :                AbsoluteTime *i_end)
    1435             : {
    1436             :     char       *p,
    1437             :                *p1;
    1438             :     char        c;
    1439             : 
    1440          12 :     p = i_string;
    1441             :     /* skip leading blanks up to '[' */
    1442          24 :     while ((c = *p) != '\0')
    1443             :     {
    1444          12 :         if (IsSpace(c))
    1445           0 :             p++;
    1446          12 :         else if (c != '[')
    1447           0 :             goto bogus;         /* syntax error */
    1448             :         else
    1449          12 :             break;
    1450             :     }
    1451          12 :     if (c == '\0')
    1452           0 :         goto bogus;             /* syntax error */
    1453          12 :     p++;
    1454             :     /* skip leading blanks up to '"' */
    1455          24 :     while ((c = *p) != '\0')
    1456             :     {
    1457          12 :         if (IsSpace(c))
    1458           0 :             p++;
    1459          12 :         else if (c != '"')
    1460           0 :             goto bogus;         /* syntax error */
    1461             :         else
    1462          12 :             break;
    1463             :     }
    1464          12 :     if (c == '\0')
    1465           0 :         goto bogus;             /* syntax error */
    1466          12 :     p++;
    1467          12 :     if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
    1468           0 :         goto bogus;             /* undefined range, handled like a syntax err. */
    1469             :     /* search for the end of the first date and change it to a \0 */
    1470          12 :     p1 = p;
    1471         191 :     while ((c = *p1) != '\0')
    1472             :     {
    1473         179 :         if (c == '"')
    1474          12 :             break;
    1475         167 :         p1++;
    1476             :     }
    1477          12 :     if (c == '\0')
    1478           0 :         goto bogus;             /* syntax error */
    1479          12 :     *p1 = '\0';
    1480             :     /* get the first date */
    1481          12 :     *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
    1482             :                                                         CStringGetDatum(p)));
    1483             :     /* undo change to \0 */
    1484          10 :     *p1 = c;
    1485          10 :     p = ++p1;
    1486             :     /* skip blanks up to '"', beginning of second date */
    1487          30 :     while ((c = *p) != '\0')
    1488             :     {
    1489          20 :         if (IsSpace(c))
    1490          10 :             p++;
    1491          10 :         else if (c != '"')
    1492           0 :             goto bogus;         /* syntax error */
    1493             :         else
    1494          10 :             break;
    1495             :     }
    1496          10 :     if (c == '\0')
    1497           0 :         goto bogus;             /* syntax error */
    1498          10 :     p++;
    1499             :     /* search for the end of the second date and change it to a \0 */
    1500          10 :     p1 = p;
    1501         188 :     while ((c = *p1) != '\0')
    1502             :     {
    1503         178 :         if (c == '"')
    1504          10 :             break;
    1505         168 :         p1++;
    1506             :     }
    1507          10 :     if (c == '\0')
    1508           0 :         goto bogus;             /* syntax error */
    1509          10 :     *p1 = '\0';
    1510             :     /* get the second date */
    1511          10 :     *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
    1512             :                                                       CStringGetDatum(p)));
    1513             :     /* undo change to \0 */
    1514          10 :     *p1 = c;
    1515          10 :     p = ++p1;
    1516             :     /* skip blanks up to ']' */
    1517          20 :     while ((c = *p) != '\0')
    1518             :     {
    1519          10 :         if (IsSpace(c))
    1520           0 :             p++;
    1521          10 :         else if (c != ']')
    1522           0 :             goto bogus;         /* syntax error */
    1523             :         else
    1524          10 :             break;
    1525             :     }
    1526          10 :     if (c == '\0')
    1527           0 :         goto bogus;             /* syntax error */
    1528          10 :     p++;
    1529          10 :     c = *p;
    1530          10 :     if (c != '\0')
    1531           0 :         goto bogus;             /* syntax error */
    1532             : 
    1533             :     /* it seems to be a valid tinterval */
    1534          20 :     return;
    1535             : 
    1536             : bogus:
    1537           0 :     ereport(ERROR,
    1538             :             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    1539             :              errmsg("invalid input syntax for type %s: \"%s\"",
    1540             :                     "tinterval", i_string)));
    1541             :     *i_start = *i_end = INVALID_ABSTIME;    /* keep compiler quiet */
    1542             : }
    1543             : 
    1544             : 
    1545             : /*****************************************************************************
    1546             :  *
    1547             :  *****************************************************************************/
    1548             : 
    1549             : /*
    1550             :  * timeofday -
    1551             :  *     returns the current time as a text. similar to timenow() but returns
    1552             :  *     seconds with more precision (up to microsecs). (I need this to compare
    1553             :  *     the Wisconsin benchmark with Illustra whose TimeNow() shows current
    1554             :  *     time with precision up to microsecs.)              - ay 3/95
    1555             :  */
    1556             : Datum
    1557           0 : timeofday(PG_FUNCTION_ARGS)
    1558             : {
    1559             :     struct timeval tp;
    1560             :     char        templ[128];
    1561             :     char        buf[128];
    1562             :     pg_time_t   tt;
    1563             : 
    1564           0 :     gettimeofday(&tp, NULL);
    1565           0 :     tt = (pg_time_t) tp.tv_sec;
    1566           0 :     pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
    1567           0 :                 pg_localtime(&tt, session_timezone));
    1568           0 :     snprintf(buf, sizeof(buf), templ, tp.tv_usec);
    1569             : 
    1570           0 :     PG_RETURN_TEXT_P(cstring_to_text(buf));
    1571             : }

Generated by: LCOV version 1.11