]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/nabstime.c
Update copyright for 2014
[postgresql] / src / backend / utils / adt / nabstime.c
index dfab102fa76a7f9dcc65fcb08ff1769981be96fa..74d24aa06519e603f2c63526e5f15cd123d9180d 100644 (file)
@@ -5,12 +5,12 @@
  *       Functions for the built-in type "RelativeTime".
  *       Functions for the built-in type "TimeInterval".
  *
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.149 2007/01/05 22:19:41 momjian Exp $
+ *       src/backend/utils/adt/nabstime.c
  *
  *-------------------------------------------------------------------------
  */
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
+#include "utils/datetime.h"
 #include "utils/nabstime.h"
 
 #define MIN_DAYNUM (-24856)            /* December 13, 1901 */
 #define MAX_DAYNUM 24854               /* January 18, 2038 */
 
-#define INVALID_RELTIME_STR            "Undefined RelTime"
-#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
-#define RELTIME_LABEL                  '@'
-#define RELTIME_PAST                   "ago"
-#define DIRMAXLEN                              (sizeof(RELTIME_PAST)-1)
-
 /*
  * Unix epoch is Jan  1 00:00:00 1970.
  * Postgres knows about times sixty-eight years on either side of that
@@ -86,6 +81,8 @@ static void parsetinterval(char *i_string,
  * GetCurrentAbsoluteTime()
  *
  * Get the current system time (relative to Unix epoch).
+ *
+ * NB: this will overflow in 2038; it should be gone long before that.
  */
 AbsoluteTime
 GetCurrentAbsoluteTime(void)
@@ -103,16 +100,8 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
        pg_time_t       time = (pg_time_t) _time;
        struct pg_tm *tx;
 
-       /*
-        * If HasCTZSet is true then we have a brute force time zone specified. Go
-        * ahead and rotate to the local time zone since we will later bypass any
-        * calls which adjust the tm fields.
-        */
-       if (HasCTZSet && (tzp != NULL))
-               time -= CTimeZone;
-
-       if (!HasCTZSet && tzp != NULL)
-               tx = pg_localtime(&time, global_timezone);
+       if (tzp != NULL)
+               tx = pg_localtime(&time, session_timezone);
        else
                tx = pg_gmtime(&time);
 
@@ -129,21 +118,6 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
 
        if (tzp != NULL)
        {
-               /*
-                * We have a brute force time zone per SQL99? Then use it without
-                * change since we have already rotated to the time zone.
-                */
-               if (HasCTZSet)
-               {
-                       *tzp = CTimeZone;
-                       tm->tm_gmtoff = CTimeZone;
-                       tm->tm_isdst = 0;
-                       tm->tm_zone = NULL;
-                       if (tzn != NULL)
-                               *tzn = NULL;
-               }
-               else
-               {
                        *tzp = -tm->tm_gmtoff;          /* tm_gmtoff is Sun/DEC-ism */
 
                        /*
@@ -164,7 +138,6 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
                                                         errmsg("invalid time zone name: \"%s\"",
                                                                        tm->tm_zone)));
                        }
-               }
        }
        else
                tm->tm_isdst = -1;
@@ -183,13 +156,13 @@ tm2abstime(struct pg_tm * tm, int tz)
 
        /* validate, before going out of range on some members */
        if (tm->tm_year < 1901 || tm->tm_year > 2038 ||
-               tm->tm_mon < 1 || tm->tm_mon > 12 ||
+               tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR ||
                tm->tm_mday < 1 || tm->tm_mday > 31 ||
                tm->tm_hour < 0 ||
-               tm->tm_hour > 24 ||             /* test for > 24:00:00 */
-               (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
-               tm->tm_min < 0 || tm->tm_min > 59 ||
-               tm->tm_sec < 0 || tm->tm_sec > 60)
+               tm->tm_hour > HOURS_PER_DAY ||  /* test for > 24:00:00 */
+         (tm->tm_hour == HOURS_PER_DAY && (tm->tm_min > 0 || tm->tm_sec > 0)) ||
+               tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
+               tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE)
                return INVALID_ABSTIME;
 
        day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
@@ -314,7 +287,7 @@ abstimeout(PG_FUNCTION_ARGS)
                        break;
                default:
                        abstime2tm(time, &tz, tm, &tzn);
-                       EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
+                       EncodeDateTime(tm, fsec, true, tz, tzn, DateStyle, buf);
                        break;
        }
 
@@ -474,7 +447,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
                result = NOEND_ABSTIME;
        else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
        {
-               tz = DetermineTimeZoneOffset(tm, global_timezone);
+               tz = DetermineTimeZoneOffset(tm, session_timezone);
                result = tm2abstime(tm, tz);
        }
        else
@@ -630,7 +603,14 @@ reltimein(PG_FUNCTION_ARGS)
        dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
                                                  field, ftype, MAXDATEFIELDS, &nf);
        if (dterr == 0)
-               dterr = DecodeInterval(field, ftype, nf, &dtype, tm, &fsec);
+               dterr = DecodeInterval(field, ftype, nf, INTERVAL_FULL_RANGE,
+                                                          &dtype, tm, &fsec);
+
+       /* if those functions think it's a bad format, try ISO8601 style */
+       if (dterr == DTERR_BAD_FORMAT)
+               dterr = DecodeISO8601Interval(str,
+                                                                         &dtype, tm, &fsec);
+
        if (dterr != 0)
        {
                if (dterr == DTERR_FIELD_OVERFLOW)
@@ -668,7 +648,7 @@ reltimeout(PG_FUNCTION_ARGS)
        char            buf[MAXDATELEN + 1];
 
        reltime2tm(time, tm);
-       EncodeInterval(tm, 0, DateStyle, buf);
+       EncodeInterval(tm, 0, IntervalStyle, buf);
 
        result = pstrdup(buf);
        PG_RETURN_CSTRING(result);
@@ -783,20 +763,25 @@ tintervalrecv(PG_FUNCTION_ARGS)
 {
        StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
        TimeInterval tinterval;
+       int32           status;
 
        tinterval = (TimeInterval) palloc(sizeof(TimeIntervalData));
 
        tinterval->status = pq_getmsgint(buf, sizeof(tinterval->status));
+       tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
+       tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
+
+       if (tinterval->data[0] == INVALID_ABSTIME ||
+               tinterval->data[1] == INVALID_ABSTIME)
+               status = T_INTERVAL_INVAL;              /* undefined  */
+       else
+               status = T_INTERVAL_VALID;
 
-       if (!(tinterval->status == T_INTERVAL_INVAL ||
-                 tinterval->status == T_INTERVAL_VALID))
+       if (status != tinterval->status)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                                 errmsg("invalid status in external \"tinterval\" value")));
 
-       tinterval->data[0] = pq_getmsgint(buf, sizeof(tinterval->data[0]));
-       tinterval->data[1] = pq_getmsgint(buf, sizeof(tinterval->data[1]));
-
        PG_RETURN_TIMEINTERVAL(tinterval);
 }
 
@@ -829,12 +814,7 @@ interval_reltime(PG_FUNCTION_ARGS)
        int                     year,
                                month,
                                day;
-
-#ifdef HAVE_INT64_TIMESTAMP
-       int64           span;
-#else
-       double          span;
-#endif
+       TimeOffset      span;
 
        year = interval->month / MONTHS_PER_YEAR;
        month = interval->month % MONTHS_PER_YEAR;
@@ -1029,12 +1009,7 @@ tintervalrel(PG_FUNCTION_ARGS)
 Datum
 timenow(PG_FUNCTION_ARGS)
 {
-       time_t          sec;
-
-       if (time(&sec) < 0)
-               PG_RETURN_ABSOLUTETIME(INVALID_ABSTIME);
-
-       PG_RETURN_ABSOLUTETIME((AbsoluteTime) sec);
+       PG_RETURN_ABSOLUTETIME(GetCurrentAbsoluteTime());
 }
 
 /*
@@ -1157,9 +1132,22 @@ tintervalsame(PG_FUNCTION_ARGS)
 /*
  * tinterval comparison routines
  *
- * Note: comparison is based on the lengths of the tintervals, not on
- * endpoint value.     This is pretty bogus, but since it's only a legacy
- * datatype I'm not going to propose changing it.
+ * Note: comparison is based only on the lengths of the tintervals, not on
+ * endpoint values (as long as they're not INVALID).  This is pretty bogus,
+ * but since it's only a legacy datatype, we're not going to change it.
+ *
+ * Some other bogus things that won't be changed for compatibility reasons:
+ * 1. The interval length computations overflow at 2^31 seconds, causing
+ * intervals longer than that to sort oddly compared to those shorter.
+ * 2. infinity and minus infinity (NOEND_ABSTIME and NOSTART_ABSTIME) are
+ * just ordinary integers.     Since this code doesn't handle them specially,
+ * it's possible for [a b] to be considered longer than [c infinity] for
+ * finite abstimes a, b, c.  In combination with the previous point, the
+ * interval [-infinity infinity] is treated as being shorter than many finite
+ * intervals :-(
+ *
+ * If tinterval is ever reimplemented atop timestamp, it'd be good to give
+ * some consideration to avoiding these problems.
  */
 static int
 tinterval_cmp_internal(TimeInterval a, TimeInterval b)
@@ -1584,19 +1572,13 @@ timeofday(PG_FUNCTION_ARGS)
        struct timeval tp;
        char            templ[128];
        char            buf[128];
-       text       *result;
-       int                     len;
        pg_time_t       tt;
 
        gettimeofday(&tp, NULL);
        tt = (pg_time_t) tp.tv_sec;
        pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
-                               pg_localtime(&tt, global_timezone));
+                               pg_localtime(&tt, session_timezone));
        snprintf(buf, sizeof(buf), templ, tp.tv_usec);
 
-       len = VARHDRSZ + strlen(buf);
-       result = (text *) palloc(len);
-       VARATT_SIZEP(result) = len;
-       memcpy(VARDATA(result), buf, strlen(buf));
-       PG_RETURN_TEXT_P(result);
+       PG_RETURN_TEXT_P(cstring_to_text(buf));
 }