Support alternate storage scheme of 64-bit integer for date/time types.
authorThomas G. Lockhart <[email protected]>
Sun, 21 Apr 2002 19:48:31 +0000 (19:48 +0000)
committerThomas G. Lockhart <[email protected]>
Sun, 21 Apr 2002 19:48:31 +0000 (19:48 +0000)
 Use "--enable-integer-datetimes" in configuration to use this rather
 than the original float8 storage. I would recommend the integer-based
 storage for any platform on which it is available. We perhaps should
 make this the default for the production release.
Change timezone(timestamptz) results to return timestamp rather than
 a character string. Formerly, we didn't have a way to represent
 timestamps with an explicit time zone other than freezing the info into
 a string. Now, we can reasonably omit the explicit time zone from the
 result and return a timestamp with values appropriate for the specified
 time zone. Much cleaner, and if you need the time zone in the result
 you can put it into a character string pretty easily anyway.
Allow fractional seconds in date/time types even for dates prior to 1BC.
Limit timestamp data types to 6 decimal places of precision. Just right
 for a micro-second storage of int8 date/time types, and reduces the
 number of places ad-hoc rounding was occuring for the float8-based types.
Use lookup tables for precision/rounding calculations for timestamp and
 interval types.  Formerly used pow() to calculate the desired value but
 with a more limited range there is no reason to not type in a lookup
 table. Should be *much* better performance, though formerly there were
 some optimizations to help minimize the number of times pow() was called.
Define a HAVE_INT64_TIMESTAMP variable. Based on the configure option
 "--enable-integer-datetimes" and the existing internal INT64_IS_BUSTED.
Add explicit date/interval operators and functions for addition and
 subtraction. Formerly relied on implicit type promotion from date to
 timestamp with time zone.
Change timezone conversion functions for the timetz type from "timetz()"
 to "timezone()". This is consistant with other time zone coersion
 functions for other types.
Bump the catalog version to 200204201.
Fix up regression tests to reflect changes in fractional seconds
 representation for date/times in BC eras.
All regression tests pass on my Linux box.

17 files changed:
src/backend/utils/adt/date.c
src/backend/utils/adt/datetime.c
src/backend/utils/adt/formatting.c
src/backend/utils/adt/int8.c
src/backend/utils/adt/nabstime.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/adt/timestamp.c
src/include/c.h
src/include/catalog/catversion.h
src/include/catalog/pg_control.h
src/include/catalog/pg_operator.h
src/include/catalog/pg_proc.h
src/include/pg_config.h.in
src/include/utils/date.h
src/include/utils/datetime.h
src/include/utils/int8.h
src/include/utils/timestamp.h

index 7971a1fa35ce0075c77a9e4617682aa6a557db45..76b6bf80c09d880387608a340e10df1dd13178a0 100644 (file)
 #include "utils/timestamp.h"
 
 
+int time2tm(TimeADT time, struct tm * tm, fsec_t *fsec);
+int timetz2tm(TimeTzADT *time, struct tm * tm, fsec_t *fsec, int *tzp);
+int tm2time(struct tm * tm, fsec_t fsec, TimeADT *result);
+int tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result);
 static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
 
 /*****************************************************************************
@@ -43,7 +47,7 @@ date_in(PG_FUNCTION_ARGS)
 {
        char       *str = PG_GETARG_CSTRING(0);
        DateADT         date;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     tzp;
@@ -221,6 +225,60 @@ date_mii(PG_FUNCTION_ARGS)
        PG_RETURN_DATEADT(dateVal - days);
 }
 
+#if NOT_USED
+/* date_pl_interval() and date_mi_interval() are probably
+ * better implmented by converting the input date
+ * to timestamp without time zone. So that is what we do
+ * in pg_proc.h - thomas 2002-03-11
+ */
+
+/* Add an interval to a date, giving a new date.
+ * Must handle both positive and negative intervals.
+ */
+Datum
+date_pl_interval(PG_FUNCTION_ARGS)
+{
+       DateADT         dateVal = PG_GETARG_DATEADT(0);
+       Interval   *span = PG_GETARG_INTERVAL_P(1);
+       struct tm       tt,
+                          *tm = &tt;
+
+       if (span->month != 0)
+       {
+               j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+               tm->tm_mon += span->month;
+               dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+       }
+       if (span->time != 0)
+               dateVal += (span->time / 86400e0);
+
+       PG_RETURN_DATEADT(dateVal);
+}
+
+/* Subtract an interval from a date, giving a new date.
+ * Must handle both positive and negative intervals.
+ */
+Datum
+date_mi_interval(PG_FUNCTION_ARGS)
+{
+       DateADT         dateVal = PG_GETARG_DATEADT(0);
+       Interval   *span = PG_GETARG_INTERVAL_P(1);
+       struct tm       tt,
+                          *tm = &tt;
+
+       if (span->month != 0)
+       {
+               j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+               tm->tm_mon -= span->month;
+               dateVal = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+       }
+       if (span->time != 0)
+               dateVal -= (span->time / 86400e0);
+
+       PG_RETURN_DATEADT(dateVal);
+}
+#endif
+
 /* date_timestamp()
  * Convert date to timestamp data type.
  */
@@ -230,8 +288,13 @@ date_timestamp(PG_FUNCTION_ARGS)
        DateADT         dateVal = PG_GETARG_DATEADT(0);
        Timestamp       result;
 
+#ifdef HAVE_INT64_TIMESTAMP
+       /* date is days since 2000, timestamp is microseconds since same... */
+       result = dateVal * INT64CONST(86400000000);
+#else
        /* date is days since 2000, timestamp is seconds since same... */
        result = dateVal * 86400.0;
+#endif
 
        PG_RETURN_TIMESTAMP(result);
 }
@@ -245,17 +308,23 @@ timestamp_date(PG_FUNCTION_ARGS)
 {
        Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
        DateADT         result;
+#if 0
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
+#endif
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
+#if 0
        if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
                elog(ERROR, "Unable to convert timestamp to date");
 
        result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+#else
+       result = (timestamp / INT64CONST(86400000000));
+#endif
 
        PG_RETURN_DATEADT(result);
 }
@@ -289,15 +358,29 @@ date_timestamptz(PG_FUNCTION_ARGS)
                if (utime == -1)
                        elog(ERROR, "Unable to convert date to tm");
 
+#ifdef HAVE_INT64_TIMESTAMP
+               result = ((utime * INT64CONST(1000000))
+                                 + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * INT64CONST(86400000000)));
+#else
                result = utime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400.0);
+#endif
+#else
+#ifdef HAVE_INT64_TIMESTAMP
+               result = ((dateVal * INT64CONST(86400000000))
+                       + (CTimeZone * INT64CONST(1000000)));
 #else
                result = dateVal * 86400.0 + CTimeZone;
+#endif
 #endif
        }
        else
        {
+#ifdef HAVE_INT64_TIMESTAMP
+               result = (dateVal * INT64CONST(86400000000));
+#else
                /* Outside of range for timezone support, so assume UTC */
                result = dateVal * 86400.0;
+#endif
        }
 
        PG_RETURN_TIMESTAMP(result);
@@ -314,7 +397,7 @@ timestamptz_date(PG_FUNCTION_ARGS)
        DateADT         result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        int                     tz;
        char       *tzn;
 
@@ -427,13 +510,12 @@ Datum
 time_in(PG_FUNCTION_ARGS)
 {
        char       *str = PG_GETARG_CSTRING(0);
-
 #ifdef NOT_USED
        Oid                     typelem = PG_GETARG_OID(1);
 #endif
        int32           typmod = PG_GETARG_INT32(2);
        TimeADT         result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     nf;
@@ -446,13 +528,56 @@ time_in(PG_FUNCTION_ARGS)
         || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec, NULL) != 0))
                elog(ERROR, "Bad time external representation '%s'", str);
 
-       result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
-
+       tm2time(tm, fsec, &result);
        AdjustTimeForTypmod(&result, typmod);
 
        PG_RETURN_TIMEADT(result);
 }
 
+/* tm2time()
+ * Convert a tm structure to a time data type.
+ */
+int
+tm2time(struct tm * tm, fsec_t fsec, TimeADT *result)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+       *result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+                          * INT64CONST(1000000)) + fsec);
+#else
+       *result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+       return 0;
+}
+
+/* time2tm()
+ * Convert time data type to POSIX time structure.
+ * For dates within the system-supported time_t range, convert to the
+ *     local time zone. If out of this range, leave as GMT. - tgl 97/05/27
+ */
+int
+time2tm(TimeADT time, struct tm *tm, fsec_t *fsec)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+       tm->tm_hour = (time / INT64CONST(3600000000));
+       time -= (tm->tm_hour * INT64CONST(3600000000));
+       tm->tm_min = (time / INT64CONST(60000000));
+       time -= (tm->tm_min * INT64CONST(60000000));
+       tm->tm_sec = (time / INT64CONST(1000000));
+       time -= (tm->tm_sec * INT64CONST(1000000));
+       *fsec = time;
+#else
+       double          trem;
+
+       trem = time;
+       TMODULO(trem, tm->tm_hour, 3600e0);
+       TMODULO(trem, tm->tm_min, 60e0);
+       TMODULO(trem, tm->tm_sec, 1e0);
+       *fsec = trem;
+#endif
+
+       return 0;
+}
+
 Datum
 time_out(PG_FUNCTION_ARGS)
 {
@@ -460,16 +585,10 @@ time_out(PG_FUNCTION_ARGS)
        char       *result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
-       double          trem;
+       fsec_t          fsec;
        char            buf[MAXDATELEN + 1];
 
-       trem = time;
-       TMODULO(trem, tm->tm_hour, 3600e0);
-       TMODULO(trem, tm->tm_min, 60e0);
-       TMODULO(trem, tm->tm_sec, 1e0);
-       fsec = trem;
-
+       time2tm(time, tm, &fsec);
        EncodeTimeOnly(tm, fsec, NULL, DateStyle, buf);
 
        result = pstrdup(buf);
@@ -496,21 +615,35 @@ time_scale(PG_FUNCTION_ARGS)
 static void
 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
 {
-       if ((typmod >= 0) && (typmod <= 13))
+       if ((typmod >= 0) && (typmod <= MAX_TIME_PRECISION))
        {
+#ifdef HAVE_INT64_TIMESTAMP
+               static int64 TimeScale = INT64CONST(1000000);
+#else
                static double TimeScale = 1;
+#endif
                static int32 TimeTypmod = 0;
 
                if (typmod != TimeTypmod)
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       TimeScale = pow(10.0, (MAX_TIME_PRECISION-typmod));
+#else
                        TimeScale = pow(10.0, typmod);
+#endif
                        TimeTypmod = typmod;
                }
 
+#ifdef HAVE_INT64_TIMESTAMP
+               *time = ((*time / TimeScale) * TimeScale);
+               if (*time >= INT64CONST(86400000000))
+                       *time -= INT64CONST(86400000000);
+#else
                *time = (rint(((double) *time) * TimeScale) / TimeScale);
 
                if (*time >= 86400)
                        *time -= 86400;
+#endif
        }
 
        return;
@@ -738,15 +871,56 @@ timestamp_time(PG_FUNCTION_ARGS)
        TimeADT         result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
        if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) != 0)
-               elog(ERROR, "Unable to convert timestamp to date");
+               elog(ERROR, "Unable to convert timestamp to time");
+
+#ifdef HAVE_INT64_TIMESTAMP
+       /* Could also do this with
+        * time = (timestamp / 86400000000 * 86400000000) - timestamp;
+        */
+       result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+                          * INT64CONST(1000000)) + fsec);
+#else
+       result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+
+       PG_RETURN_TIMEADT(result);
+}
+
+/* timestamptz_time()
+ * Convert timestamptz to time data type.
+ */
+Datum
+timestamptz_time(PG_FUNCTION_ARGS)
+{
+       TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
+       TimeADT         result;
+       struct tm       tt,
+                          *tm = &tt;
+       int                     tz;
+       fsec_t          fsec;
+       char       *tzn;
 
+       if (TIMESTAMP_NOT_FINITE(timestamp))
+               PG_RETURN_NULL();
+
+       if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
+               elog(ERROR, "Unable to convert timestamptz to time");
+
+#ifdef HAVE_INT64_TIMESTAMP
+       /* Could also do this with
+        * time = (timestamp / 86400000000 * 86400000000) - timestamp;
+        */
+       result = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+                          * INT64CONST(1000000)) + fsec);
+#else
        result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
 
        PG_RETURN_TIMEADT(result);
 }
@@ -793,10 +967,18 @@ interval_time(PG_FUNCTION_ARGS)
 {
        Interval   *span = PG_GETARG_INTERVAL_P(0);
        TimeADT         result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+       result = span->time;
+       if ((result >= INT64CONST(86400000000))
+               || (result <= INT64CONST(-86400000000)))
+               result -= (result / INT64CONST(1000000) * INT64CONST(1000000));
+#else
        Interval        span1;
 
        result = span->time;
        TMODULO(result, span1.time, 86400e0);
+#endif
 
        PG_RETURN_TIMEADT(result);
 }
@@ -813,7 +995,7 @@ time_mi_time(PG_FUNCTION_ARGS)
 
        result = (Interval *) palloc(sizeof(Interval));
 
-       result->time = time1 - time2;
+       result->time = (time1 - time2);
        result->month = 0;
 
        PG_RETURN_INTERVAL_P(result);
@@ -828,12 +1010,20 @@ time_pl_interval(PG_FUNCTION_ARGS)
        TimeADT         time = PG_GETARG_TIMEADT(0);
        Interval   *span = PG_GETARG_INTERVAL_P(1);
        TimeADT         result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+       result = (time + span->time);
+       result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
+       if (result < INT64CONST(0))
+               result += INT64CONST(86400000000);
+#else
        TimeADT         time1;
 
        result = (time + span->time);
        TMODULO(result, time1, 86400e0);
        if (result < 0)
                result += 86400;
+#endif
 
        PG_RETURN_TIMEADT(result);
 }
@@ -847,12 +1037,20 @@ time_mi_interval(PG_FUNCTION_ARGS)
        TimeADT         time = PG_GETARG_TIMEADT(0);
        Interval   *span = PG_GETARG_INTERVAL_P(1);
        TimeADT         result;
+
+#ifdef HAVE_INT64_TIMESTAMP
+       result = (time - span->time);
+       result -= (result / INT64CONST(86400000000) * INT64CONST(86400000000));
+       if (result < INT64CONST(0))
+               result += INT64CONST(86400000000);
+#else
        TimeADT         time1;
 
        result = (time - span->time);
        TMODULO(result, time1, 86400e0);
        if (result < 0)
                result += 86400;
+#endif
 
        PG_RETURN_TIMEADT(result);
 }
@@ -926,11 +1124,137 @@ text_time(PG_FUNCTION_ARGS)
                                                           Int32GetDatum(-1));
 }
 
+/* time_part()
+ * Extract specified field from time type.
+ */
+Datum
+time_part(PG_FUNCTION_ARGS)
+{
+       text       *units = PG_GETARG_TEXT_P(0);
+       TimeADT         time = PG_GETARG_TIMEADT(1);
+       float8          result;
+       int                     type,
+                               val;
+       int                     i;
+       char       *up,
+                          *lp,
+                               lowunits[MAXDATELEN + 1];
+
+       if (VARSIZE(units) - VARHDRSZ > MAXDATELEN)
+               elog(ERROR, "TIME units '%s' not recognized",
+                        DatumGetCString(DirectFunctionCall1(textout,
+                                                                                          PointerGetDatum(units))));
+       up = VARDATA(units);
+       lp = lowunits;
+       for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+               *lp++ = tolower((unsigned char) *up++);
+       *lp = '\0';
+
+       type = DecodeUnits(0, lowunits, &val);
+       if (type == UNKNOWN_FIELD)
+               type = DecodeSpecial(0, lowunits, &val);
+
+       if (type == UNITS)
+       {
+               fsec_t          fsec;
+               struct tm       tt,
+                                  *tm = &tt;
+
+               time2tm(time, tm, &fsec);
+
+               switch (val)
+               {
+                       case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
+#else
+                               result = ((tm->tm_sec + fsec) * 1000000);
+#endif
+                               break;
+
+                       case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * INT64CONST(1000))
+                                                 + (fsec / INT64CONST(1000)));
+#else
+                               result = ((tm->tm_sec + fsec) * 1000);
+#endif
+                               break;
+
+                       case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
+#else
+                               result = (tm->tm_sec + fsec);
+#endif
+                               break;
+
+                       case DTK_MINUTE:
+                               result = tm->tm_min;
+                               break;
+
+                       case DTK_HOUR:
+                               result = tm->tm_hour;
+                               break;
+
+                       case DTK_TZ:
+                       case DTK_TZ_MINUTE:
+                       case DTK_TZ_HOUR:
+                       case DTK_DAY:
+                       case DTK_MONTH:
+                       case DTK_QUARTER:
+                       case DTK_YEAR:
+                       case DTK_DECADE:
+                       case DTK_CENTURY:
+                       case DTK_MILLENNIUM:
+                       default:
+                               elog(ERROR, "TIME units '%s' not supported",
+                                        DatumGetCString(DirectFunctionCall1(textout,
+                                                                                          PointerGetDatum(units))));
+                               result = 0;
+               }
+       }
+       else if ((type == RESERV) && (val == DTK_EPOCH))
+       {
+#ifdef HAVE_INT64_TIMESTAMP
+               result = (time / 1000000e0);
+#else
+               result = time;
+#endif
+       }
+       else
+       {
+               elog(ERROR, "TIME units '%s' not recognized",
+                        DatumGetCString(DirectFunctionCall1(textout,
+                                                                                          PointerGetDatum(units))));
+               result = 0;
+       }
+
+       PG_RETURN_FLOAT8(result);
+}
+
 
 /*****************************************************************************
  *      Time With Time Zone ADT
  *****************************************************************************/
 
+/* tm2timetz()
+ * Convert a tm structure to a time data type.
+ */
+int
+tm2timetz(struct tm * tm, fsec_t fsec, int tz, TimeTzADT *result)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = ((((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec)
+                                        * INT64CONST(1000000)) + fsec);
+#else
+       result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
+#endif
+       result->zone = tz;
+
+       return 0;
+}
+
 Datum
 timetz_in(PG_FUNCTION_ARGS)
 {
@@ -941,7 +1265,7 @@ timetz_in(PG_FUNCTION_ARGS)
 #endif
        int32           typmod = PG_GETARG_INT32(2);
        TimeTzADT  *result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     tz;
@@ -956,10 +1280,7 @@ timetz_in(PG_FUNCTION_ARGS)
                elog(ERROR, "Bad time external representation '%s'", str);
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
-
-       result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
-       result->zone = tz;
-
+       tm2timetz(tm, fsec, tz, result);
        AdjustTimeForTypmod(&(result->time), typmod);
 
        PG_RETURN_TIMETZADT_P(result);
@@ -972,23 +1293,46 @@ timetz_out(PG_FUNCTION_ARGS)
        char       *result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        int                     tz;
-       double          trem;
        char            buf[MAXDATELEN + 1];
 
+       timetz2tm(time, tm, &fsec, &tz);
+       EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
+
+       result = pstrdup(buf);
+       PG_RETURN_CSTRING(result);
+}
+
+/* timetz2tm()
+ * Convert TIME WITH TIME ZONE data type to POSIX time structure.
+ * For dates within the system-supported time_t range, convert to the
+ *     local time zone. If out of this range, leave as GMT. - tgl 97/05/27
+ */
+int
+timetz2tm(TimeTzADT *time, struct tm *tm, fsec_t *fsec, int *tzp)
+{
+#ifdef HAVE_INT64_TIMESTAMP
+       tm->tm_hour = (time->time / INT64CONST(3600000000));
+       time->time -= (tm->tm_hour * INT64CONST(3600000000));
+       tm->tm_min = (time->time / INT64CONST(60000000));
+       time->time -= (tm->tm_min * INT64CONST(60000000));
+       tm->tm_sec = (time->time / INT64CONST(1000000));
+       *fsec = (time->time - (tm->tm_sec * INT64CONST(1000000)));
+#else
+       double          trem;
+
        trem = time->time;
        TMODULO(trem, tm->tm_hour, 3600e0);
        TMODULO(trem, tm->tm_min, 60e0);
        TMODULO(trem, tm->tm_sec, 1e0);
-       fsec = trem;
-
-       tz = time->zone;
+       *fsec = trem;
+#endif
 
-       EncodeTimeOnly(tm, fsec, &tz, DateStyle, buf);
+       if (tzp != NULL)
+               *tzp = time->zone;
 
-       result = pstrdup(buf);
-       PG_RETURN_CSTRING(result);
+       return 0;
 }
 
 /* timetz_scale()
@@ -1116,7 +1460,7 @@ timetz_hash(PG_FUNCTION_ARGS)
         * sizeof(TimeTzADT), so that any garbage pad bytes in the structure
         * won't be included in the hash!
         */
-       return hash_any((unsigned char *) key, sizeof(double) + sizeof(int4));
+       return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->zone));
 }
 
 Datum
@@ -1154,14 +1498,24 @@ timetz_pl_interval(PG_FUNCTION_ARGS)
        TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
        Interval   *span = PG_GETARG_INTERVAL_P(1);
        TimeTzADT  *result;
+#ifndef HAVE_INT64_TIMESTAMP
        TimeTzADT       time1;
+#endif
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = (time->time + span->time);
+       result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
+       if (result->time < INT64CONST(0))
+               result->time += INT64CONST(86400000000);
+#else
        result->time = (time->time + span->time);
        TMODULO(result->time, time1.time, 86400e0);
        if (result->time < 0)
                result->time += 86400;
+#endif
+
        result->zone = time->zone;
 
        PG_RETURN_TIMETZADT_P(result);
@@ -1176,14 +1530,24 @@ timetz_mi_interval(PG_FUNCTION_ARGS)
        TimeTzADT  *time = PG_GETARG_TIMETZADT_P(0);
        Interval   *span = PG_GETARG_INTERVAL_P(1);
        TimeTzADT  *result;
+#ifndef HAVE_INT64_TIMESTAMP
        TimeTzADT       time1;
+#endif
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = (time->time - span->time);
+       result->time -= (result->time / INT64CONST(86400000000) * INT64CONST(86400000000));
+       if (result->time < INT64CONST(0))
+               result->time += INT64CONST(86400000000);
+#else
        result->time = (time->time - span->time);
        TMODULO(result->time, time1.time, 86400e0);
        if (result->time < 0)
                result->time += 86400;
+#endif
+
        result->zone = time->zone;
 
        PG_RETURN_TIMETZADT_P(result);
@@ -1336,9 +1700,11 @@ time_timetz(PG_FUNCTION_ARGS)
        TimeTzADT  *result;
        struct tm       tt,
                           *tm = &tt;
+       fsec_t          fsec;
        int                     tz;
 
        GetCurrentTime(tm);
+       time2tm(time, tm, &fsec);
        tz = DetermineLocalTimeZone(tm);
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
@@ -1361,19 +1727,18 @@ timestamptz_timetz(PG_FUNCTION_ARGS)
        struct tm       tt,
                           *tm = &tt;
        int                     tz;
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
                PG_RETURN_NULL();
 
        if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) != 0)
-               elog(ERROR, "Unable to convert timestamp to date");
+               elog(ERROR, "Unable to convert timestamptz to timetz");
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
-       result->time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
-       result->zone = tz;
+       tm2timetz(tm, fsec, tz, result);
 
        PG_RETURN_TIMETZADT_P(result);
 }
@@ -1392,7 +1757,12 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS)
        TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
        TimestampTz result;
 
-       result = date * 86400.0 + time->time + time->zone;
+#ifdef HAVE_INT64_TIMESTAMP
+       result = (((date * INT64CONST(86400000000)) + time->time)
+               + (time->zone * INT64CONST(1000000)));
+#else
+       result = (((date * 86400.0) + time->time) + time->zone);
+#endif
 
        PG_RETURN_TIMESTAMP(result);
 }
@@ -1486,19 +1856,13 @@ timetz_part(PG_FUNCTION_ARGS)
 
        if (type == UNITS)
        {
-               double          trem;
                double          dummy;
                int                     tz;
-               double          fsec;
+               fsec_t          fsec;
                struct tm       tt,
                                   *tm = &tt;
 
-               trem = time->time;
-               TMODULO(trem, tm->tm_hour, 3600e0);
-               TMODULO(trem, tm->tm_min, 60e0);
-               TMODULO(trem, tm->tm_sec, 1e0);
-               fsec = trem;
-               tz = time->zone;
+               timetz2tm(time, tm, &fsec, &tz);
 
                switch (val)
                {
@@ -1517,15 +1881,28 @@ timetz_part(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * INT64CONST(1000000)) + fsec);
+#else
                                result = ((tm->tm_sec + fsec) * 1000000);
+#endif
                                break;
 
                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * INT64CONST(1000))
+                                                 + (fsec / INT64CONST(1000)));
+#else
                                result = ((tm->tm_sec + fsec) * 1000);
+#endif
                                break;
 
                        case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = (tm->tm_sec + (fsec / INT64CONST(1000000)));
+#else
                                result = (tm->tm_sec + fsec);
+#endif
                                break;
 
                        case DTK_MINUTE:
@@ -1551,7 +1928,13 @@ timetz_part(PG_FUNCTION_ARGS)
                }
        }
        else if ((type == RESERV) && (val == DTK_EPOCH))
-               result = time->time - time->zone;
+       {
+#ifdef HAVE_INT64_TIMESTAMP
+               result = ((time->time / 1000000e0) - time->zone);
+#else
+               result = (time->time - time->zone);
+#endif
+       }
        else
        {
                elog(ERROR, "TIMETZ units '%s' not recognized",
@@ -1598,10 +1981,18 @@ timetz_zone(PG_FUNCTION_ARGS)
        if ((type == TZ) || (type == DTZ))
        {
                tz = val * 60;
-               time1 = time->time - time->zone + tz;
+#ifdef HAVE_INT64_TIMESTAMP
+               time1 = (time->time - ((time->zone + tz) * INT64CONST(1000000)));
+               result->time -= ((result->time / time1) * time1);
+               if (result->time < INT64CONST(0))
+                       result->time += INT64CONST(86400000000);
+#else
+               time1 = (time->time - time->zone + tz);
                TMODULO(result->time, time1, 86400e0);
                if (result->time < 0)
                        result->time += 86400;
+#endif
+
                result->zone = tz;
        }
        else
@@ -1622,7 +2013,6 @@ timetz_izone(PG_FUNCTION_ARGS)
        Interval   *zone = PG_GETARG_INTERVAL_P(0);
        TimeTzADT  *time = PG_GETARG_TIMETZADT_P(1);
        TimeTzADT  *result;
-       TimeADT         time1;
        int                     tz;
 
        if (zone->month != 0)
@@ -1630,14 +2020,28 @@ timetz_izone(PG_FUNCTION_ARGS)
                         DatumGetCString(DirectFunctionCall1(interval_out,
                                                                                                 PointerGetDatum(zone))));
 
+#ifdef HAVE_INT64_TIMESTAMP
+       tz = -(zone->time / INT64CONST(1000000));
+#else
        tz = -(zone->time);
+#endif
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
-       time1 = time->time - time->zone + tz;
-       TMODULO(result->time, time1, 86400e0);
-       if (result->time < 0)
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = (time->time + ((time->zone - tz) * INT64CONST(1000000)));
+       while (result->time < INT64CONST(0))
+               result->time += INT64CONST(86400000000);
+       while (result->time >= INT64CONST(86400000000))
+               result->time -= INT64CONST(86400000000);
+#else
+       result->time = (time->time + (time->zone - tz));
+       while (result->time < 0)
                result->time += 86400;
+       while (result->time >= 86400)
+               result->time -= 86400;
+#endif
+
        result->zone = tz;
 
        PG_RETURN_TIMETZADT_P(result);
index e15cbea323aff9dd8690388d961292df8cf7f741..5a9ab4820630839972efdce1193ad5cad79698a7 100644 (file)
 
 static int DecodeNumber(int flen, char *field,
                         int fmask, int *tmask,
-                        struct tm * tm, double *fsec, int *is2digits);
+                        struct tm * tm, fsec_t *fsec, int *is2digits);
 static int DecodeNumberField(int len, char *str,
                                  int fmask, int *tmask,
-                                 struct tm * tm, double *fsec, int *is2digits);
+                                 struct tm * tm, fsec_t *fsec, int *is2digits);
 static int DecodeTime(char *str, int fmask, int *tmask,
-                  struct tm * tm, double *fsec);
+                  struct tm * tm, fsec_t *fsec);
 static int     DecodeTimezone(char *str, int *tzp);
 static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
 static int     DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
@@ -865,7 +865,7 @@ ParseDateTime(char *timestr, char *lowstr,
  */
 int
 DecodeDateTime(char **field, int *ftype, int nf,
-                          int *dtype, struct tm * tm, double *fsec, int *tzp)
+                          int *dtype, struct tm * tm, fsec_t *fsec, int *tzp)
 {
        int                     fmask = 0,
                                tmask,
@@ -1095,9 +1095,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                        tmask = DTK_M(SECOND);
                                                        if (*cp == '.')
                                                        {
-                                                               *fsec = strtod(cp, &cp);
+                                                               double frac;
+                                                               frac = strtod(cp, &cp);
                                                                if (*cp != '\0')
                                                                        return -1;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                               *fsec = frac * 1000000;
+#else
+                                                               *fsec = frac;
+#endif
                                                        }
                                                        break;
 
@@ -1113,6 +1119,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                         ***/
                                                        tmask = DTK_DATE_M;
                                                        j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+                                                       /* fractional Julian Day? */
                                                        if (*cp == '.')
                                                        {
                                                                double time;
@@ -1122,9 +1129,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
                                                                        return -1;
 
                                                                tmask |= DTK_TIME_M;
-                                                               dt2time((time*86400), &tm->tm_hour, &tm->tm_min, fsec);
-                                                               tm->tm_sec = *fsec;
-                                                               *fsec -= tm->tm_sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                               dt2time((time*86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#else
+                                                               dt2time((time*86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#endif
                                                        }
                                                        break;
 
@@ -1505,7 +1514,7 @@ DetermineLocalTimeZone(struct tm * tm)
  */
 int
 DecodeTimeOnly(char **field, int *ftype, int nf,
-                          int *dtype, struct tm * tm, double *fsec, int *tzp)
+                          int *dtype, struct tm * tm, fsec_t *fsec, int *tzp)
 {
        int                     fmask = 0,
                                tmask,
@@ -1729,9 +1738,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
                                                                        return -1;
 
                                                                tmask |= DTK_TIME_M;
-                                                               dt2time((time*86400), &tm->tm_hour, &tm->tm_min, fsec);
-                                                               tm->tm_sec = *fsec;
-                                                               *fsec -= tm->tm_sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                               dt2time((time*86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#else
+                                                               dt2time((time*86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
+#endif
                                                        }
                                                        break;
 
@@ -1925,10 +1936,18 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
        else if ((mer == PM) && (tm->tm_hour != 12))
                tm->tm_hour += 12;
 
+#ifdef HAVE_INT64_TIMESTAMP
+       if (((tm->tm_hour < 0) || (tm->tm_hour > 23))
+               || ((tm->tm_min < 0) || (tm->tm_min > 59))
+               || ((tm->tm_sec < 0) || (tm->tm_sec > 60))
+               || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
+               return -1;
+#else
        if (((tm->tm_hour < 0) || (tm->tm_hour > 23))
                || ((tm->tm_min < 0) || (tm->tm_min > 59))
                || ((tm->tm_sec < 0) || ((tm->tm_sec + *fsec) >= 60)))
                return -1;
+#endif
 
        if ((fmask & DTK_TIME_M) != DTK_TIME_M)
                return -1;
@@ -1973,7 +1992,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
 static int
 DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
 {
-       double          fsec;
+       fsec_t          fsec;
 
        int                     nf = 0;
        int                     i,
@@ -2100,7 +2119,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
  *     can be used to represent time spans.
  */
 static int
-DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
+DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
 {
        char       *cp;
 
@@ -2115,12 +2134,10 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
        {
                tm->tm_sec = 0;
                *fsec = 0;
-
        }
        else if (*cp != ':')
        {
                return -1;
-
        }
        else
        {
@@ -2130,9 +2147,22 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
                        *fsec = 0;
                else if (*cp == '.')
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       char fstr[MAXDATELEN + 1];
+
+                       /* OK, we have at most six digits to work with.
+                        * Let's construct a string and then do the conversion
+                        * to an integer.
+                        */
+                       strncpy(fstr, (cp+1), 7);
+                       strcpy((fstr+strlen(fstr)), "000000");
+                       *(fstr+6) = '\0';
+                       *fsec = strtol(fstr, &cp, 10);
+#else
                        str = cp;
                        *fsec = strtod(str, &cp);
-                       if (cp == str)
+#endif
+                       if (*cp != '\0')
                                return -1;
                }
                else
@@ -2140,10 +2170,19 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
        }
 
        /* do a sanity check */
+#ifdef HAVE_INT64_TIMESTAMP
+       if ((tm->tm_hour < 0)
+               || (tm->tm_min < 0) || (tm->tm_min > 59)
+               || (tm->tm_sec < 0) || (tm->tm_sec > 59)
+               || (*fsec >= INT64CONST(1000000)))
+               return -1;
+#else
        if ((tm->tm_hour < 0)
                || (tm->tm_min < 0) || (tm->tm_min > 59)
-               || (tm->tm_sec < 0) || (tm->tm_sec > 59))
+               || (tm->tm_sec < 0) || (tm->tm_sec > 59)
+               || (*fsec >= 1))
                return -1;
+#endif
 
        return 0;
 }      /* DecodeTime() */
@@ -2154,7 +2193,7 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
  */
 static int
 DecodeNumber(int flen, char *str, int fmask,
-                        int *tmask, struct tm * tm, double *fsec, int *is2digits)
+                        int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits)
 {
        int                     val;
        char       *cp;
@@ -2193,7 +2232,6 @@ DecodeNumber(int flen, char *str, int fmask,
                tm->tm_yday = val;
                j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
                           &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
-
        }
 
        /***
@@ -2225,7 +2263,6 @@ DecodeNumber(int flen, char *str, int fmask,
        {
                *tmask = DTK_M(MONTH);
                tm->tm_mon = val;
-
        }
        /* no year and EuroDates enabled? then could be day */
        else if ((EuroDates || (fmask & DTK_M(MONTH)))
@@ -2275,7 +2312,7 @@ DecodeNumber(int flen, char *str, int fmask,
  */
 static int
 DecodeNumberField(int len, char *str, int fmask,
-                                 int *tmask, struct tm * tm, double *fsec, int *is2digits)
+                                 int *tmask, struct tm * tm, fsec_t *fsec, int *is2digits)
 {
        char       *cp;
 
@@ -2284,7 +2321,20 @@ DecodeNumberField(int len, char *str, int fmask,
         */
        if ((cp = strchr(str, '.')) != NULL)
        {
+#ifdef HAVE_INT64_TIMESTAMP
+                       char fstr[MAXDATELEN + 1];
+
+                       /* OK, we have at most six digits to care about.
+                        * Let's construct a string and then do the conversion
+                        * to an integer.
+                        */
+                       strcpy(fstr, (cp+1));
+                       strcpy((fstr+strlen(fstr)), "000000");
+                       *(fstr+6) = '\0';
+                       *fsec = strtol(fstr, NULL, 10);
+#else
                *fsec = strtod(cp, NULL);
+#endif
                *cp = '\0';
                len = strlen(str);
        }
@@ -2501,7 +2551,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
 }      /* DecodeSpecial() */
 
 
-/* DecodeDateDelta()
+/* DecodeInterval()
  * Interpret previously parsed fields for general time interval.
  * Return 0 if decoded and -1 if problems.
  *
@@ -2512,7 +2562,7 @@ DecodeSpecial(int field, char *lowtoken, int *val)
  *     preceding an hh:mm:ss field. - thomas 1998-04-30
  */
 int
-DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, double *fsec)
+DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec)
 {
        int                     is_before = FALSE;
 
@@ -2523,7 +2573,6 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
        int                     i;
        int                     val;
        double          fval;
-       double          sec;
 
        *dtype = DTK_DELTA;
 
@@ -2631,51 +2680,113 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
                                switch (type)
                                {
                                        case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                                               *fsec += (val + fval);
+#else
                                                *fsec += ((val + fval) * 1e-6);
+#endif
                                                break;
 
                                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                                               *fsec += ((val + fval) * 1000);
+#else
                                                *fsec += ((val + fval) * 1e-3);
+#endif
                                                break;
 
                                        case DTK_SECOND:
                                                tm->tm_sec += val;
+#ifdef HAVE_INT64_TIMESTAMP
+                                               *fsec += (fval * 1000000);
+#else
                                                *fsec += fval;
+#endif
                                                tmask = DTK_M(SECOND);
                                                break;
 
                                        case DTK_MINUTE:
                                                tm->tm_min += val;
                                                if (fval != 0)
-                                                       tm->tm_sec += (fval * 60);
+                                               {
+                                                       int sec;
+                                                       fval *= 60;
+                                                       sec = fval;
+                                                       tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                       *fsec += ((fval - sec) * 1000000);
+#else
+                                                       *fsec += (fval - sec);
+#endif
+                                               }
                                                tmask = DTK_M(MINUTE);
                                                break;
 
                                        case DTK_HOUR:
                                                tm->tm_hour += val;
                                                if (fval != 0)
-                                                       tm->tm_sec += (fval * 3600);
+                                               {
+                                                       int sec;
+                                                       fval *= 3600;
+                                                       sec = fval;
+                                                       tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                       *fsec += ((fval - sec) * 1000000);
+#else
+                                                       *fsec += (fval - sec);
+#endif
+                                               }
                                                tmask = DTK_M(HOUR);
                                                break;
 
                                        case DTK_DAY:
                                                tm->tm_mday += val;
                                                if (fval != 0)
-                                                       tm->tm_sec += (fval * 86400);
+                                               {
+                                                       int sec;
+                                                       fval *= 86400;
+                                                       sec = fval;
+                                                       tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                       *fsec += ((fval - sec) * 1000000);
+#else
+                                                       *fsec += (fval - sec);
+#endif
+                                               }
                                                tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
                                                break;
 
                                        case DTK_WEEK:
                                                tm->tm_mday += val * 7;
                                                if (fval != 0)
-                                                       tm->tm_sec += (fval * (7 * 86400));
+                                               {
+                                                       int sec;
+                                                       fval *= (7*86400);
+                                                       sec = fval;
+                                                       tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                       *fsec += ((fval - sec) * 1000000);
+#else
+                                                       *fsec += (fval - sec);
+#endif
+                                               }
                                                tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
                                                break;
 
                                        case DTK_MONTH:
                                                tm->tm_mon += val;
                                                if (fval != 0)
-                                                       tm->tm_sec += (fval * (30 * 86400));
+                                               {
+                                                       int sec;
+                                                       fval *= (30*86400);
+                                                       sec = fval;
+                                                       tm->tm_sec += sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                                                       *fsec += ((fval - sec) * 1000000);
+#else
+                                                       *fsec += (fval - sec);
+#endif
+                                               }
                                                tmask = DTK_M(MONTH);
                                                break;
 
@@ -2751,7 +2862,14 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
 
        if (*fsec != 0)
        {
+               int             sec;
+
+#ifdef HAVE_INT64_TIMESTAMP
+               sec = (*fsec / INT64CONST(1000000));
+               *fsec -= (sec * INT64CONST(1000000));
+#else
                TMODULO(*fsec, sec, 1e0);
+#endif
                tm->tm_sec += sec;
        }
 
@@ -2768,7 +2886,7 @@ DecodeDateDelta(char **field, int *ftype, int nf, int *dtype, struct tm * tm, do
 
        /* ensure that at least one time field has been found */
        return (fmask != 0) ? 0 : -1;
-}      /* DecodeDateDelta() */
+}      /* DecodeInterval() */
 
 
 /* DecodeUnits()
@@ -2899,14 +3017,18 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
  * Encode time fields only.
  */
 int
-EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
+EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str)
 {
-       double          sec;
+#ifndef HAVE_INT64_TIMESTAMP
+       fsec_t          sec;
+#endif
 
        if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
                return -1;
 
+#ifndef HAVE_INT64_TIMESTAMP
        sec = (tm->tm_sec + fsec);
+#endif
 
        sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
 
@@ -2919,14 +3041,23 @@ EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
         */
        if (fsec != 0)
        {
+#ifdef HAVE_INT64_TIMESTAMP
+               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+               sprintf((str + strlen(str)), ".%06d", fsec);
+#else
                sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
                /* chop off trailing pairs of zeros... */
                while ((strcmp((str + strlen(str) - 2), "00") == 0)
                           && (*(str + strlen(str) - 3) != '.'))
                        *(str + strlen(str) - 2) = '\0';
        }
        else
+#ifdef HAVE_INT64_TIMESTAMP
+               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+#else
                sprintf((str + strlen(str)), ":%02.0f", sec);
+#endif
 
        if (tzp != NULL)
        {
@@ -2954,158 +3085,191 @@ EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str)
  *     European - dd/mm/yyyy
  */
 int
-EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str)
+EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str)
 {
        int                     day,
                                hour,
                                min;
-       double          sec;
+#ifndef HAVE_INT64_TIMESTAMP
+       fsec_t          sec;
+#endif
 
-       if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
-               return -1;
+       /* Why are we checking only the month field? Change this to an assert...
+        * if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+        *  return -1;
+        */
+       Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
 
+#ifndef HAVE_INT64_TIMESTAMP
        sec = (tm->tm_sec + fsec);
+#endif
 
        switch (style)
        {
-                       /* compatible with ISO date formats */
-
                case USE_ISO_DATES:
-                       if (tm->tm_year > 0)
-                       {
-                               sprintf(str, "%04d-%02d-%02d %02d:%02d",
-                                               tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
+                       /* Compatible with ISO-8601 date formats */
 
-                               /*
-                                * If we have fractional seconds, then include a decimal
-                                * point We will do up to 6 fractional digits, and we have
-                                * rounded any inputs to eliminate anything to the right
-                                * of 6 digits anyway. If there are no fractional seconds,
-                                * then do not bother printing a decimal point at all. -
-                                * thomas 2001-09-29
-                                */
-                               if (fsec != 0)
-                               {
-                                       sprintf((str + strlen(str)), ":%013.10f", sec);
-                                       TrimTrailingZeros(str);
-                               }
-                               else
-                                       sprintf((str + strlen(str)), ":%02.0f", sec);
+                       sprintf(str, "%04d-%02d-%02d %02d:%02d",
+                                       ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+                                       tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
 
-                               /*
-                                * tzp == NULL indicates that we don't want *any* time
-                                * zone info in the output string. *tzn != NULL indicates
-                                * that we have alpha time zone info available. tm_isdst
-                                * != -1 indicates that we have a valid time zone
-                                * translation.
-                                */
-                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
-                               {
-                                       hour = -(*tzp / 3600);
-                                       min = ((abs(*tzp) / 60) % 60);
-                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
-                               }
+                       /*
+                        * If we have fractional seconds, then include a decimal
+                        * point We will do up to 6 fractional digits, and we have
+                        * rounded any inputs to eliminate anything to the right
+                        * of 6 digits anyway. If there are no fractional seconds,
+                        * then do not bother printing a decimal point at all. -
+                        * thomas 2001-09-29
+                        */
+#ifdef HAVE_INT64_TIMESTAMP
+                       if (fsec != 0)
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                               sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+                       if ((fsec != 0) && (tm->tm_year > 0))
+                       {
+                               sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+                               TrimTrailingZeros(str);
                        }
                        else
                        {
-                               if (tm->tm_hour || tm->tm_min)
-                                       sprintf(str, "%04d-%02d-%02d %02d:%02d %s",
-                                                       -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC");
-                               else
-                                       sprintf(str, "%04d-%02d-%02d %s",
-                                         -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                       }
+
+                       if (tm->tm_year <= 0)
+                       {
+                               sprintf((str + strlen(str)), " BC");
+                       }
+
+                       /*
+                        * tzp == NULL indicates that we don't want *any* time
+                        * zone info in the output string.
+                        * *tzn != NULL indicates that we have alpha time zone
+                        * info available.
+                        * tm_isdst != -1 indicates that we have a valid time zone
+                        * translation.
+                        */
+                       if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       {
+                               hour = -(*tzp / 3600);
+                               min = ((abs(*tzp) / 60) % 60);
+                               sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
                        }
                        break;
 
-                       /* compatible with Oracle/Ingres date formats */
                case USE_SQL_DATES:
+                       /* Compatible with Oracle/Ingres date formats */
+
                        if (EuroDates)
                                sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
                        else
                                sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
 
-                       if (tm->tm_year > 0)
+                       sprintf((str + 5), "/%04d %02d:%02d",
+                                       ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+                                       tm->tm_hour, tm->tm_min);
+
+                       /*
+                        * If we have fractional seconds, then include a decimal
+                        * point We will do up to 6 fractional digits, and we have
+                        * rounded any inputs to eliminate anything to the right
+                        * of 6 digits anyway. If there are no fractional seconds,
+                        * then do not bother printing a decimal point at all. -
+                        * thomas 2001-09-29
+                        */
+#ifdef HAVE_INT64_TIMESTAMP
+                       if (fsec != 0)
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                               sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+                       if ((fsec != 0) && (tm->tm_year > 0))
                        {
-                               sprintf((str + 5), "/%04d %02d:%02d",
-                                               tm->tm_year, tm->tm_hour, tm->tm_min);
+                               sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+                               TrimTrailingZeros(str);
+                       }
+                       else
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                       }
 
-                               /*
-                                * If we have fractional seconds, then include a decimal
-                                * point We will do up to 6 fractional digits, and we have
-                                * rounded any inputs to eliminate anything to the right
-                                * of 6 digits anyway. If there are no fractional seconds,
-                                * then do not bother printing a decimal point at all. -
-                                * thomas 2001-09-29
-                                */
-                               if (fsec != 0)
-                               {
-                                       sprintf((str + strlen(str)), ":%013.10f", sec);
-                                       TrimTrailingZeros(str);
-                               }
-                               else
-                                       sprintf((str + strlen(str)), ":%02.0f", sec);
+                       if (tm->tm_year <= 0)
+                       {
+                               sprintf((str + strlen(str)), " BC");
+                       }
 
-                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       {
+                               if (*tzn != NULL)
+                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                               else
                                {
-                                       if (*tzn != NULL)
-                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-                                       else
-                                       {
-                                               hour = -(*tzp / 3600);
-                                               min = ((abs(*tzp) / 60) % 60);
-                                               sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
-                                       }
+                                       hour = -(*tzp / 3600);
+                                       min = ((abs(*tzp) / 60) % 60);
+                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
                                }
                        }
-                       else
-                               sprintf((str + 5), "/%04d %02d:%02d %s",
-                                         -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
                        break;
 
-                       /* German variant on European style */
                case USE_GERMAN_DATES:
+                       /* German variant on European style */
+
                        sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
-                       if (tm->tm_year > 0)
+
+                       sprintf((str + 5), ".%04d %02d:%02d",
+                                       ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)),
+                                       tm->tm_hour, tm->tm_min);
+
+                       /*
+                        * If we have fractional seconds, then include a decimal
+                        * point We will do up to 6 fractional digits, and we have
+                        * rounded any inputs to eliminate anything to the right
+                        * of 6 digits anyway. If there are no fractional seconds,
+                        * then do not bother printing a decimal point at all. -
+                        * thomas 2001-09-29
+                        */
+#ifdef HAVE_INT64_TIMESTAMP
+                       if (fsec != 0)
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                               sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+                       if ((fsec != 0) && (tm->tm_year > 0))
+                       {
+                               sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+                               TrimTrailingZeros(str);
+                       }
+                       else
                        {
-                               sprintf((str + 5), ".%04d %02d:%02d",
-                                               tm->tm_year, tm->tm_hour, tm->tm_min);
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                       }
 
-                               /*
-                                * If we have fractional seconds, then include a decimal
-                                * point We will do up to 6 fractional digits, and we have
-                                * rounded any inputs to eliminate anything to the right
-                                * of 6 digits anyway. If there are no fractional seconds,
-                                * then do not bother printing a decimal point at all. -
-                                * thomas 2001-09-29
-                                */
-                               if (fsec != 0)
-                               {
-                                       sprintf((str + strlen(str)), ":%013.10f", sec);
-                                       TrimTrailingZeros(str);
-                               }
-                               else
-                                       sprintf((str + strlen(str)), ":%02.0f", sec);
+                       if (tm->tm_year <= 0)
+                       {
+                               sprintf((str + strlen(str)), " BC");
+                       }
 
-                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       {
+                               if (*tzn != NULL)
+                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                               else
                                {
-                                       if (*tzn != NULL)
-                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-                                       else
-                                       {
-                                               hour = -(*tzp / 3600);
-                                               min = ((abs(*tzp) / 60) % 60);
-                                               sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
-                                       }
+                                       hour = -(*tzp / 3600);
+                                       min = ((abs(*tzp) / 60) % 60);
+                                       sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
                                }
                        }
-                       else
-                               sprintf((str + 5), ".%04d %02d:%02d %s",
-                                         -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
                        break;
 
-                       /* backward-compatible with traditional Postgres abstime dates */
                case USE_POSTGRES_DATES:
                default:
+                       /* Backward-compatible with traditional Postgres abstime dates */
+
                        day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
                        tm->tm_wday = j2day(day);
 
@@ -3117,52 +3281,58 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
                        else
                                sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
 
-                       if (tm->tm_year > 0)
-                       {
-                               sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
+                       sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
 
-                               /*
-                                * If we have fractional seconds, then include a decimal
-                                * point We will do up to 6 fractional digits, and we have
-                                * rounded any inputs to eliminate anything to the right
-                                * of 6 digits anyway. If there are no fractional seconds,
-                                * then do not bother printing a decimal point at all. -
-                                * thomas 2001-09-29
-                                */
-                               if (fsec != 0)
-                               {
-                                       sprintf((str + strlen(str)), ":%013.10f", sec);
-                                       TrimTrailingZeros(str);
-                               }
-                               else
-                                       sprintf((str + strlen(str)), ":%02.0f", sec);
+                       /*
+                        * If we have fractional seconds, then include a decimal
+                        * point We will do up to 6 fractional digits, and we have
+                        * rounded any inputs to eliminate anything to the right
+                        * of 6 digits anyway. If there are no fractional seconds,
+                        * then do not bother printing a decimal point at all. -
+                        * thomas 2001-09-29
+                        */
+#ifdef HAVE_INT64_TIMESTAMP
+                       if (fsec != 0)
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                               sprintf((str + strlen(str)), ".%06d", fsec);
+#else
+                       if ((fsec != 0) && (tm->tm_year > 0))
+                       {
+                               sprintf((str + strlen(str)), ":%013.10f", sec);
+#endif
+                               TrimTrailingZeros(str);
+                       }
+                       else
+                       {
+                               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
+                       }
 
-                               sprintf((str + strlen(str)), " %04d", tm->tm_year);
+                       sprintf((str + strlen(str)), " %04d",
+                                       ((tm->tm_year > 0)? tm->tm_year: -(tm->tm_year - 1)));
+                       if (tm->tm_year <= 0)
+                       {
+                               sprintf((str + strlen(str)), " BC");
+                       }
 
-                               if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       if ((tzp != NULL) && (tm->tm_isdst >= 0))
+                       {
+                               if (*tzn != NULL)
+                                       sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
+                               else
                                {
-                                       if (*tzn != NULL)
-                                               sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
-                                       else
-                                       {
-                                               /*
-                                                * We have a time zone, but no string version. Use
-                                                * the numeric form, but be sure to include a
-                                                * leading space to avoid formatting something
-                                                * which would be rejected by the date/time parser
-                                                * later. - thomas 2001-10-19
-                                                */
-                                               hour = -(*tzp / 3600);
-                                               min = ((abs(*tzp) / 60) % 60);
-                                               sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
-                                       }
+                                       /*
+                                        * We have a time zone, but no string version. Use
+                                        * the numeric form, but be sure to include a
+                                        * leading space to avoid formatting something
+                                        * which would be rejected by the date/time parser
+                                        * later. - thomas 2001-10-19
+                                        */
+                                       hour = -(*tzp / 3600);
+                                       min = ((abs(*tzp) / 60) % 60);
+                                       sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
                                }
                        }
-                       else
-                       {
-                               sprintf((str + 10), " %02d:%02d %04d %s",
-                                         tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC");
-                       }
                        break;
        }
 
@@ -3170,7 +3340,7 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
 }      /* EncodeDateTime() */
 
 
-/* EncodeTimeSpan()
+/* EncodeInterval()
  * Interpret time structure as a delta time and convert to string.
  *
  * Support "traditional Postgres" and ISO-8601 styles.
@@ -3179,7 +3349,7 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha
  * - thomas 1998-04-30
  */
 int
-EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
+EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str)
 {
        int                     is_before = FALSE;
        int                     is_nonzero = FALSE;
@@ -3239,8 +3409,14 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
                                /* fractional seconds? */
                                if (fsec != 0)
                                {
+#ifdef HAVE_INT64_TIMESTAMP
+                                       sprintf(cp, ":%02d", abs(tm->tm_sec));
+                                       cp += strlen(cp);
+                                       sprintf(cp, ".%06d", ((fsec >= 0)? fsec: -(fsec)));
+#else
                                        fsec += tm->tm_sec;
                                        sprintf(cp, ":%013.10f", fabs(fsec));
+#endif
                                        TrimTrailingZeros(cp);
                                        cp += strlen(cp);
                                        is_nonzero = TRUE;
@@ -3336,7 +3512,16 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
                        /* fractional seconds? */
                        if (fsec != 0)
                        {
-                               double          sec;
+#ifdef HAVE_INT64_TIMESTAMP
+                               if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
+                                       tm->tm_sec = -tm->tm_sec;
+                               sprintf(cp, "%s%d.%02d secs", (is_nonzero ? " " : ""),
+                                               tm->tm_sec, (((int) fsec) / 10000));
+                               cp += strlen(cp);
+                               if (!is_nonzero)
+                                       is_before = (fsec < 0);
+#else
+                               fsec_t          sec;
 
                                fsec += tm->tm_sec;
                                sec = fsec;
@@ -3347,6 +3532,7 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
                                cp += strlen(cp);
                                if (!is_nonzero)
                                        is_before = (fsec < 0);
+#endif
                                is_nonzero = TRUE;
 
                                /* otherwise, integer seconds only? */
@@ -3382,7 +3568,7 @@ EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
        }
 
        return 0;
-}      /* EncodeTimeSpan() */
+}      /* EncodeInterval() */
 
 
 void
index e2b444d90517e6b39581e4135dd8d92f31493bc3..4e29e909b98fdbb52baa7f7e5eb263181ccff266 100644 (file)
@@ -410,7 +410,7 @@ typedef struct
 typedef struct TmToChar
 {
        struct tm       tm;                             /* classic 'tm' struct */
-       double          fsec;                   /* milliseconds */
+       fsec_t          fsec;                   /* fractional seconds */
        char       *tzn;                        /* timezone */
 } TmToChar;
 
@@ -1831,7 +1831,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
                case DCH_MS:                    /* millisecond */
                        if (flag == TO_CHAR)
                        {
+#ifdef HAVE_INT64_TIMESTAMP
+                               sprintf(inout, "%03d", (int) (tmtc->fsec / INT64CONST(1000)));
+#else
                                sprintf(inout, "%03d", (int) rint(tmtc->fsec * 1000));
+#endif
                                if (S_THth(suf))
                                        str_numth(p_inout, inout, S_TH_TYPE(suf));
                                if (S_THth(suf))
@@ -1874,7 +1878,11 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node, void *data)
                case DCH_US:                    /* microsecond */
                        if (flag == TO_CHAR)
                        {
+#ifdef HAVE_INT64_TIMESTAMP
+                               sprintf(inout, "%06d", (int) tmtc->fsec);
+#else
                                sprintf(inout, "%06d", (int) rint(tmtc->fsec * 1000000));
+#endif
                                if (S_THth(suf))
                                        str_numth(p_inout, inout, S_TH_TYPE(suf));
                                if (S_THth(suf))
@@ -2868,7 +2876,7 @@ to_timestamp(PG_FUNCTION_ARGS)
                                date_len,
                                tz = 0;
        struct tm       tm;
-       double          fsec = 0;
+       fsec_t          fsec = 0;
 
        ZERO_tm(&tm);
        ZERO_tmfc(&tmfc);
@@ -3071,10 +3079,17 @@ to_timestamp(PG_FUNCTION_ARGS)
                                tm.tm_yday - y[i - 1];
        }
 
+#ifdef HAVE_INT64_TIMESTAMP
+       if (tmfc.ms)
+               fsec += tmfc.ms * 1000;
+       if (tmfc.us)
+               fsec += tmfc.us;
+#else
        if (tmfc.ms)
                fsec += (double) tmfc.ms / 1000;
        if (tmfc.us)
                fsec += (double) tmfc.us / 1000000;
+#endif
 
        /* -------------------------------------------------------------- */
 
index ee0fc88e44d87778195210a7be0f6938a0fa03dd..2e346a59042ca25850f6070284cfe9541bc40530 100644 (file)
@@ -23,6 +23,7 @@
 
 /* this should be set in pg_config.h, but just in case it wasn't: */
 #ifndef INT64_FORMAT
+#warning "Broken pg_config.h should have defined INT64_FORMAT"
 #define INT64_FORMAT "%ld"
 #endif
 
index 11c13c6c572edcb5812e4f9985351262f0598c76..3a15a8ced358250f15ad2a5a26f1e5fa7714c2a6 100644 (file)
                                  AbsoluteTimeGetDatum(t1), \
                                  AbsoluteTimeGetDatum(t2))) ? (t2) : (t1))
 
-#ifdef NOT_USED
-static char *unit_tab[] = {
-       "second", "seconds", "minute", "minutes",
-       "hour", "hours", "day", "days", "week", "weeks",
-"month", "months", "year", "years"};
-
-#define UNITMAXLEN 7                   /* max length of a unit name */
-#define NUNITS 14                              /* number of different units */
-
-/* table of seconds per unit (month = 30 days, year = 365 days)  */
-static int     sec_tab[] = {
-       1, 1, 60, 60,
-       3600, 3600, 86400, 86400, 604800, 604800,
-2592000, 2592000, 31536000, 31536000};
-#endif
 
 /*
  * Function prototypes -- internal to this file only
@@ -98,12 +83,6 @@ static int   sec_tab[] = {
 
 static AbsoluteTime tm2abstime(struct tm * tm, int tz);
 static void reltime2tm(RelativeTime time, struct tm * tm);
-
-#ifdef NOT_USED
-static int     correct_unit(char *unit, int *unptr);
-static int     correct_dir(char *direction, int *signptr);
-#endif
-
 static int istinterval(char *i_string,
                        AbsoluteTime *i_start,
                        AbsoluteTime *i_end);
@@ -177,7 +156,7 @@ GetCurrentAbsoluteTime(void)
 }      /* GetCurrentAbsoluteTime() */
 
 
-/* GetCurrentAbsoluteTime()
+/* GetCurrentAbsoluteTimeUsec()
  * Get the current system time. Set timezone parameters if not specified elsewhere.
  * Define HasCTZSet to allow clients to specify the default timezone.
  *
@@ -271,13 +250,17 @@ GetCurrentTime(struct tm * tm)
 
 
 void
-GetCurrentTimeUsec(struct tm * tm, double *fsec)
+GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec)
 {
        int                     tz;
        int                     usec;
 
        abstime2tm(GetCurrentTransactionStartTimeUsec(&usec), &tz, tm, NULL);
+#ifdef HAVE_INT64_TIMESTAMP
+       *fsec = usec;
+#else
        *fsec = usec * 1.0e-6;
+#endif
 
        return;
 }      /* GetCurrentTimeUsec() */
@@ -493,7 +476,7 @@ nabstimein(PG_FUNCTION_ARGS)
 {
        char       *str = PG_GETARG_CSTRING(0);
        AbsoluteTime result;
-       double          fsec;
+       fsec_t          fsec;
        int                     tz = 0;
        struct tm       date,
                           *tm = &date;
@@ -713,7 +696,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
 {
        Timestamp       timestamp = PG_GETARG_TIMESTAMP(0);
        AbsoluteTime result;
-       double          fsec;
+       fsec_t          fsec;
        int                     tz;
        struct tm       tt,
                           *tm = &tt;
@@ -767,7 +750,9 @@ abstime_timestamp(PG_FUNCTION_ARGS)
 
                default:
                        abstime2tm(abstime, &tz, tm, &tzn);
-                       result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400) + tz;
+                       if (tm2timestamp(tm, 0, NULL, &result) != 0)
+                               elog(ERROR, "Unable convert ABSTIME to TIMESTAMP"
+                                        "\n\tabstime_timestamp() internal error");
                        break;
        };
 
@@ -783,7 +768,7 @@ timestamptz_abstime(PG_FUNCTION_ARGS)
 {
        TimestampTz timestamp = PG_GETARG_TIMESTAMP(0);
        AbsoluteTime result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
 
@@ -810,6 +795,11 @@ abstime_timestamptz(PG_FUNCTION_ARGS)
 {
        AbsoluteTime abstime = PG_GETARG_ABSOLUTETIME(0);
        TimestampTz result;
+       struct tm       tt,
+                          *tm = &tt;
+       int                     tz;
+       char            zone[MAXDATELEN + 1],
+                          *tzn = zone;
 
        switch (abstime)
        {
@@ -827,7 +817,10 @@ abstime_timestamptz(PG_FUNCTION_ARGS)
                        break;
 
                default:
-                       result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
+                       abstime2tm(abstime, &tz, tm, &tzn);
+                       if (tm2timestamp(tm, 0, &tz, &result) != 0)
+                               elog(ERROR, "Unable convert ABSTIME to TIMESTAMP WITH TIME ZONE"
+                                        "\n\tabstime_timestamp() internal error");
                        break;
        };
 
@@ -849,7 +842,7 @@ reltimein(PG_FUNCTION_ARGS)
        RelativeTime result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        int                     dtype;
        char       *field[MAXDATEFIELDS];
        int                     nf,
@@ -860,14 +853,14 @@ reltimein(PG_FUNCTION_ARGS)
                elog(ERROR, "Bad (length) reltime external representation '%s'", str);
 
        if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
-               || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+               || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
                elog(ERROR, "Bad reltime external representation '%s'", str);
 
        switch (dtype)
        {
                case DTK_DELTA:
                        result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
-                       result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60));
+                       result += ((tm->tm_year * 36525 * 864) + (((tm->tm_mon * 30) + tm->tm_mday) * 86400));
                        break;
 
                default:
@@ -893,7 +886,7 @@ reltimeout(PG_FUNCTION_ARGS)
        char            buf[MAXDATELEN + 1];
 
        reltime2tm(time, tm);
-       EncodeTimeSpan(tm, 0, DateStyle, buf);
+       EncodeInterval(tm, 0, DateStyle, buf);
 
        result = pstrdup(buf);
        PG_RETURN_CSTRING(result);
@@ -903,7 +896,7 @@ reltimeout(PG_FUNCTION_ARGS)
 static void
 reltime2tm(RelativeTime time, struct tm * tm)
 {
-       TMODULO(time, tm->tm_year, 31536000);
+       TMODULO(time, tm->tm_year, 31557600);
        TMODULO(time, tm->tm_mon, 2592000);
        TMODULO(time, tm->tm_mday, 86400);
        TMODULO(time, tm->tm_hour, 3600);
@@ -988,7 +981,11 @@ interval_reltime(PG_FUNCTION_ARGS)
        RelativeTime time;
        int                     year,
                                month;
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           span;
+#else
        double          span;
+#endif
 
        if (interval->month == 0)
        {
@@ -1006,7 +1003,13 @@ interval_reltime(PG_FUNCTION_ARGS)
                month = interval->month;
        }
 
-       span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + interval->time);
+#ifdef HAVE_INT64_TIMESTAMP
+       span = ((((INT64CONST(365250000) * year) + (INT64CONST(30000000) * month))
+                        * INT64CONST(86400)) + interval->time);
+       span /= INT64CONST(1000000);
+#else
+       span = (((((double) 365.25 * year) + ((double) 30 * month)) * 86400) + interval->time);
+#endif
 
        if ((span < INT_MIN) || (span > INT_MAX))
                time = INVALID_RELTIME;
@@ -1036,10 +1039,19 @@ reltime_interval(PG_FUNCTION_ARGS)
                        break;
 
                default:
-                       TMODULO(reltime, year, 31536000);
-                       TMODULO(reltime, month, 2592000);
+#ifdef HAVE_INT64_TIMESTAMP
+                       year = (reltime / (36525 * 864));
+                       reltime -= (year * (36525 * 864));
+                       month = (reltime / (30 * 86400));
+                       reltime -= (month * (30 * 86400));
+
+                       result->time = (reltime * INT64CONST(1000000));
+#else
+                       TMODULO(reltime, year, (36525 * 864));
+                       TMODULO(reltime, month, (30 * 86400));
 
                        result->time = reltime;
+#endif
                        result->month = ((12 * year) + month);
                        break;
        }
@@ -1090,11 +1102,6 @@ timepl(PG_FUNCTION_ARGS)
        AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
        RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
 
-#if 0
-       if (t1 == CURRENT_ABSTIME)
-               t1 = GetCurrentTransactionStartTime();
-#endif
-
        if (AbsoluteTimeIsReal(t1) &&
                RelativeTimeIsValid(t2) &&
                ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
@@ -1114,11 +1121,6 @@ timemi(PG_FUNCTION_ARGS)
        AbsoluteTime t1 = PG_GETARG_ABSOLUTETIME(0);
        RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
 
-#if 0
-       if (t1 == CURRENT_ABSTIME)
-               t1 = GetCurrentTransactionStartTime();
-#endif
-
        if (AbsoluteTimeIsReal(t1) &&
                RelativeTimeIsValid(t2) &&
                ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
index b7b6a42c51c9d8f1b35a7e2fd92678e57c1bc586..13fd021c63a536cda576531a4b7a710649ee12e8 100644 (file)
@@ -2427,17 +2427,30 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
                                 * assumed average month length of 365.25/12.0 days.  Not
                                 * too accurate, but plenty good enough for our purposes.
                                 */
+#ifdef HAVE_INT64_TIMESTAMP
+                               return (interval->time + (interval->month * ((365.25 / 12.0) * 86400000000.0)));
+#else
                                return interval->time +
                                        interval->month * (365.25 / 12.0 * 24.0 * 60.0 * 60.0);
+#endif
                        }
                case RELTIMEOID:
+#ifdef HAVE_INT64_TIMESTAMP
+                       return (DatumGetRelativeTime(value) * 1000000.0);
+#else
                        return DatumGetRelativeTime(value);
+#endif
                case TINTERVALOID:
                        {
                                TimeInterval interval = DatumGetTimeInterval(value);
 
+#ifdef HAVE_INT64_TIMESTAMP
+                               if (interval->status != 0)
+                                       return ((interval->data[1] - interval->data[0]) * 1000000.0);
+#else
                                if (interval->status != 0)
                                        return interval->data[1] - interval->data[0];
+#endif
                                return 0;               /* for lack of a better idea */
                        }
                case TIMEOID:
@@ -2447,7 +2460,11 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
                                TimeTzADT  *timetz = DatumGetTimeTzADTP(value);
 
                                /* use GMT-equivalent time */
+#ifdef HAVE_INT64_TIMESTAMP
+                               return (double) (timetz->time + (timetz->zone * 1000000.0));
+#else
                                return (double) (timetz->time + timetz->zone);
+#endif
                        }
        }
 
index 3f692d0d15566573c6a09a1ac5f3d695588a151c..d1d845695d5ee5a022719d9b0b45d1a39287ee71 100644 (file)
 #include "utils/builtins.h"
 
 
-static double time2t(const int hour, const int min, const double sec);
+#ifdef HAVE_INT64_TIMESTAMP
+static int64 time2t(const int hour, const int min, const int sec, const fsec_t fsec);
+#else
+static double time2t(const int hour, const int min, const int sec, const fsec_t fsec);
+#endif
 static int     EncodeSpecialTimestamp(Timestamp dt, char *str);
 static Timestamp dt2local(Timestamp dt, int timezone);
 static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
@@ -53,7 +57,7 @@ timestamp_in(PG_FUNCTION_ARGS)
 #endif
        int32           typmod = PG_GETARG_INT32(2);
        Timestamp       result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     tz;
@@ -111,7 +115,7 @@ timestamp_out(PG_FUNCTION_ARGS)
        char       *result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn = NULL;
        char            buf[MAXDATELEN + 1];
 
@@ -147,19 +151,81 @@ timestamp_scale(PG_FUNCTION_ARGS)
 static void
 AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
 {
-       if (!TIMESTAMP_NOT_FINITE(*time) &&
-               (typmod >= 0) && (typmod <= 13))
+#ifdef HAVE_INT64_TIMESTAMP
+       static const int64 TimestampScales[MAX_TIMESTAMP_PRECISION+1] = {
+               INT64CONST(1000000),
+               INT64CONST(100000),
+               INT64CONST(10000),
+               INT64CONST(1000),
+               INT64CONST(100),
+               INT64CONST(10),
+               INT64CONST(1)
+       };
+
+       static const int64 TimestampOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+               INT64CONST(-500000),
+               INT64CONST(-50000),
+               INT64CONST(-5000),
+               INT64CONST(-500),
+               INT64CONST(-50),
+               INT64CONST(-5),
+               INT64CONST(0)
+       };
+#else
+       static const double TimestampScales[MAX_TIMESTAMP_PRECISION+1] = {
+               1,
+               10,
+               100,
+               1000,
+               10000,
+               100000,
+               1000000
+       };
+
+       static const double TimestampOffsets[MAX_TIMESTAMP_PRECISION+1] = {
+               0.5,
+               0.05,
+               0.005,
+               0.0005,
+               0.00005,
+               0.000005,
+               0.0000005
+       };
+#endif
+
+       if (!TIMESTAMP_NOT_FINITE(*time)
+               && (typmod != -1) && (typmod != MAX_TIMESTAMP_PRECISION))
        {
-               static double TimestampScale = 1;
-               static int32 TimestampTypmod = 0;
+               if ((typmod < 0) || (typmod > MAX_TIMESTAMP_PRECISION))
+                       elog(ERROR, "TIMESTAMP(%d) precision must be between %d and %d",
+                                typmod, 0, MAX_TIMESTAMP_PRECISION);
 
-               if (typmod != TimestampTypmod)
+#ifdef HAVE_INT64_TIMESTAMP
+               /* we have different truncation behavior depending on sign */
+               if (*time >= INT64CONST(0))
                {
-                       TimestampScale = pow(10.0, typmod);
-                       TimestampTypmod = typmod;
+                       *time = ((*time / TimestampScales[typmod])
+                                        * TimestampScales[typmod]);
                }
-
-               *time = (rint(((double) *time) * TimestampScale) / TimestampScale);
+               else
+               {
+                       *time = (((*time + TimestampOffsets[typmod]) / TimestampScales[typmod])
+                                        * TimestampScales[typmod]);
+               }
+#else
+               /* we have different truncation behavior depending on sign */
+               if (*time >= 0)
+               {
+                       *time = (rint(((double) *time) * TimestampScales[typmod])
+                                        / TimestampScales[typmod]);
+               }
+               else
+               {
+                       /* Scale and truncate first, then add to help the rounding behavior */
+                       *time = (rint((((double) *time) * TimestampScales[typmod]) + TimestampOffsets[typmod])
+                                        / TimestampScales[typmod]);
+               }
+#endif
        }
 }
 
@@ -177,7 +243,7 @@ timestamptz_in(PG_FUNCTION_ARGS)
 #endif
        int32           typmod = PG_GETARG_INT32(2);
        TimestampTz result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     tz;
@@ -236,7 +302,7 @@ timestamptz_out(PG_FUNCTION_ARGS)
        int                     tz;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn;
        char            buf[MAXDATELEN + 1];
 
@@ -286,7 +352,7 @@ interval_in(PG_FUNCTION_ARGS)
 #endif
        int32           typmod = PG_GETARG_INT32(2);
        Interval   *result;
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
        int                     dtype;
@@ -304,7 +370,7 @@ interval_in(PG_FUNCTION_ARGS)
        fsec = 0;
 
        if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
-               || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+               || (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0))
                elog(ERROR, "Bad interval external representation '%s'", str);
 
        result = (Interval *) palloc(sizeof(Interval));
@@ -338,13 +404,13 @@ interval_out(PG_FUNCTION_ARGS)
        char       *result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        char            buf[MAXDATELEN + 1];
 
        if (interval2tm(*span, tm, &fsec) != 0)
                elog(ERROR, "Unable to encode interval; internal coding error");
 
-       if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
+       if (EncodeInterval(tm, fsec, DateStyle, buf) != 0)
                elog(ERROR, "Unable to format interval; internal coding error");
 
        result = pstrdup(buf);
@@ -375,6 +441,48 @@ interval_scale(PG_FUNCTION_ARGS)
 static void
 AdjustIntervalForTypmod(Interval *interval, int32 typmod)
 {
+#ifdef HAVE_INT64_TIMESTAMP
+       static const int64 IntervalScales[MAX_INTERVAL_PRECISION+1] = {
+               INT64CONST(1000000),
+               INT64CONST(100000),
+               INT64CONST(10000),
+               INT64CONST(1000),
+               INT64CONST(100),
+               INT64CONST(10),
+               INT64CONST(1)
+       };
+
+       static const int64 IntervalOffsets[MAX_INTERVAL_PRECISION+1] = {
+               INT64CONST(-500000),
+               INT64CONST(-50000),
+               INT64CONST(-5000),
+               INT64CONST(-500),
+               INT64CONST(-50),
+               INT64CONST(-5),
+               INT64CONST(0)
+       };
+#else
+       static const double IntervalScales[MAX_INTERVAL_PRECISION+1] = {
+               1000000,
+               100000,
+               10000,
+               1000,
+               100,
+               10,
+               1
+       };
+
+       static const double IntervalOffsets[MAX_INTERVAL_PRECISION+1] = {
+               -500000,
+               -50000,
+               -5000,
+               -500,
+               -50,
+               -5,
+               0
+       };
+#endif
+
        if (typmod != -1)
        {
                int                     range = ((typmod >> 16) & 0x7FFF);
@@ -396,102 +504,190 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod)
                }
                /* YEAR TO MONTH */
                else if (range == (MASK(YEAR) | MASK(MONTH)))
+               {
                        interval->time = 0;
+               }
                else if (range == MASK(DAY))
                {
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       interval->time = (((int) (interval->time / INT64CONST(86400000000)))
+                                                         * INT64CONST(86400000000));
+#else
                        interval->time = (((int) (interval->time / 86400)) * 86400);
+#endif
                }
                else if (range == MASK(HOUR))
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           day;
+#else
                        double          day;
+#endif
 
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       day = (interval->time / INT64CONST(86400000000));
+                       interval->time -= (day * INT64CONST(86400000000));
+                       interval->time = ((interval->time / INT64CONST(3600000000))
+                                                         * INT64CONST(3600000000));
+#else
                        TMODULO(interval->time, day, 86400.0);
                        interval->time = (((int) (interval->time / 3600)) * 3600.0);
+#endif
                }
                else if (range == MASK(MINUTE))
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           hour;
+#else
                        double          hour;
+#endif
 
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       hour = (interval->time / INT64CONST(3600000000));
+                       interval->time -= (hour * INT64CONST(3600000000));
+                       interval->time = ((interval->time / INT64CONST(60000000))
+                                                         * INT64CONST(60000000));
+#else
                        TMODULO(interval->time, hour, 3600.0);
                        interval->time = (((int) (interval->time / 60)) * 60);
+#endif
                }
                else if (range == MASK(SECOND))
                {
-                       double          hour;
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           minute;
+#else
+                       double          minute;
+#endif
 
                        interval->month = 0;
-                       TMODULO(interval->time, hour, 60.0);
+#ifdef HAVE_INT64_TIMESTAMP
+                       minute = (interval->time / INT64CONST(60000000));
+                       interval->time -= (minute * INT64CONST(60000000));
+#else
+                       TMODULO(interval->time, minute, 60.0);
 /*                     interval->time = (int)(interval->time); */
+#endif
                }
                /* DAY TO HOUR */
                else if (range == (MASK(DAY) | MASK(HOUR)))
                {
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       interval->time = ((interval->time / INT64CONST(3600000000))
+                                                         * INT64CONST(3600000000));
+#else
                        interval->time = (((int) (interval->time / 3600)) * 3600);
+#endif
                }
                /* DAY TO MINUTE */
                else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE)))
                {
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       interval->time = ((interval->time / INT64CONST(60000000))
+                                                         * INT64CONST(60000000));
+#else
                        interval->time = (((int) (interval->time / 60)) * 60);
+#endif
                }
                /* DAY TO SECOND */
                else if (range == (MASK(DAY) | MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
+               {
                        interval->month = 0;
+               }
                /* HOUR TO MINUTE */
                else if (range == (MASK(HOUR) | MASK(MINUTE)))
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           day;
+#else
                        double          day;
+#endif
 
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       day = (interval->time / INT64CONST(86400000000));
+                       interval->time -= (day * INT64CONST(86400000000));
+                       interval->time = ((interval->time / INT64CONST(60000000))
+                                                         * INT64CONST(60000000));
+#else
                        TMODULO(interval->time, day, 86400.0);
                        interval->time = (((int) (interval->time / 60)) * 60);
+#endif
                }
                /* HOUR TO SECOND */
                else if (range == (MASK(HOUR) | MASK(MINUTE) | MASK(SECOND)))
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           day;
+#else
                        double          day;
+#endif
 
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       day = (interval->time / INT64CONST(86400000000));
+                       interval->time -= (day * INT64CONST(86400000000));
+#else
                        TMODULO(interval->time, day, 86400.0);
+#endif
                }
                /* MINUTE TO SECOND */
                else if (range == (MASK(MINUTE) | MASK(SECOND)))
                {
+#ifdef HAVE_INT64_TIMESTAMP
+                       int64           hour;
+#else
                        double          hour;
+#endif
 
                        interval->month = 0;
+#ifdef HAVE_INT64_TIMESTAMP
+                       hour = (interval->time / INT64CONST(3600000000));
+                       interval->time -= (hour * INT64CONST(3600000000));
+#else
                        TMODULO(interval->time, hour, 3600.0);
+#endif
                }
                else
                        elog(ERROR, "AdjustIntervalForTypmod(): internal coding error");
 
+               /* Need to adjust precision? If not, don't even try! */
                if (precision != 0xFFFF)
                {
-                       static double IntervalScale = 1;
-                       static int      IntervalTypmod = 0;
+                       if ((precision < 0) || (precision > MAX_INTERVAL_PRECISION))
+                               elog(ERROR, "INTERVAL(%d) precision must be between %d and %d",
+                                        precision, 0, MAX_INTERVAL_PRECISION);
 
-                       if (precision != IntervalTypmod)
+#ifdef HAVE_INT64_TIMESTAMP
+                       /* we have different truncation behavior depending on sign */
+                       if (interval->time >= INT64CONST(0))
                        {
-                               IntervalTypmod = precision;
-                               IntervalScale = pow(10.0, IntervalTypmod);
+                               interval->time = ((interval->time / IntervalScales[precision])
+                                                                 * IntervalScales[precision]);
                        }
-
-                       /*
-                        * Hmm. For the time field, we can get to a large value since
-                        * we store everything related to an absolute interval (e.g.
-                        * years worth of days) in this one field. So we have
-                        * precision problems doing rint() on this field if the field
-                        * is too large. This resulted in an annoying "...0001"
-                        * appended to the printed result on my Linux box. I hate
-                        * doing an expensive math operation like log10() to avoid
-                        * this, but what else can we do?? - thomas 2001-10-19
-                        */
-                       if ((log10(interval->time) + IntervalTypmod) <= 13)
-                               interval->time = (rint(interval->time * IntervalScale) / IntervalScale);
+                       else
+                       {
+                               interval->time = (((interval->time + IntervalOffsets[precision]) / IntervalScales[precision])
+                                                                 * IntervalScales[precision]);
+                       }
+#else
+                       /* we have different truncation behavior depending on sign */
+                       if (interval->time >= 0)
+                       {
+                               interval->time = (rint(((double) interval->time) * IntervalScales[precision])
+                                                                 / IntervalScales[precision]);
+                       }
+                       else
+                       {
+                               interval->time = (rint((((double) interval->time) + IntervalOffsets[precision])
+                                                                          * IntervalScales[precision]) / IntervalScales[precision]);
+                       }
+#endif
                }
        }
 
@@ -524,23 +720,42 @@ now(PG_FUNCTION_ARGS)
 
        sec = GetCurrentTransactionStartTimeUsec(&usec);
 
+#ifdef HAVE_INT64_TIMESTAMP
+       result = (((sec - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400))
+                          * INT64CONST(1000000)) + usec);
+#else
        result = (sec + (usec * 1.0e-6) - ((date2j(2000, 1, 1) - date2j(1970, 1, 1)) * 86400));
+#endif
 
        PG_RETURN_TIMESTAMPTZ(result);
 }
 
 void
-dt2time(Timestamp jd, int *hour, int *min, double *sec)
+dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
 {
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           time;
+#else
        double          time;
+#endif
 
        time = jd;
 
+#ifdef HAVE_INT64_TIMESTAMP
+       *hour = (time / INT64CONST(3600000000));
+       time -= ((*hour) * INT64CONST(3600000000));
+       *min = (time / INT64CONST(60000000));
+       time -= ((*min) * INT64CONST(60000000));
+       *sec = (time / INT64CONST(1000000));
+       *fsec = (time - (*sec * INT64CONST(1000000)));
+#else
        *hour = (time / 3600);
        time -= ((*hour) * 3600);
        *min = (time / 60);
        time -= ((*min) * 60);
-       *sec = JROUND(time);
+       *sec = time;
+       *fsec = JROUND(time - *sec);
+#endif
 
        return;
 }      /* dt2time() */
@@ -558,13 +773,18 @@ dt2time(Timestamp jd, int *hour, int *min, double *sec)
  *     local time zone. If out of this range, leave as GMT. - tgl 97/05/27
  */
 int
-timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
+timestamp2tm(Timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, char **tzn)
 {
-       double          date,
-                               date0,
-                               time,
-                               sec;
-       time_t          utime;
+#ifdef HAVE_INT64_TIMESTAMP
+       int             date,
+                       date0;
+       int64   time;
+#else
+       double  date,
+                       date0;
+       double  time;
+#endif
+       time_t  utime;
 
 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
        struct tm  *tx;
@@ -578,9 +798,22 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
         * later bypass any calls which adjust the tm fields.
         */
        if (HasCTZSet && (tzp != NULL))
+#ifdef HAVE_INT64_TIMESTAMP
+               dt -= (CTimeZone * INT64CONST(1000000));
+#else
                dt -= CTimeZone;
+#endif
 
        time = dt;
+#ifdef HAVE_INT64_TIMESTAMP
+       TMODULO(time, date, INT64CONST(86400000000));
+
+       if (time < INT64CONST(0))
+       {
+               time += INT64CONST(86400000000);
+               date -= 1;
+       }
+#else
        TMODULO(time, date, 86400e0);
 
        if (time < 0)
@@ -588,6 +821,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
                time += 86400;
                date -= 1;
        }
+#endif
 
        /* Julian day routine does not work for negative Julian days */
        if (date < -date0)
@@ -597,10 +831,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
        date += date0;
 
        j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
-       dt2time(time, &tm->tm_hour, &tm->tm_min, &sec);
-
-       *fsec = JROUND(sec);
-       TMODULO(*fsec, tm->tm_sec, 1e0);
+       dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
 
        if (tzp != NULL)
        {
@@ -626,7 +857,12 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
                 */
                else if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
                {
-                       utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400);
+#ifdef HAVE_INT64_TIMESTAMP
+                       utime = ((dt / INT64CONST(1000000))
+                                        + ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400)));
+#else
+                       utime = (dt + ((date0 - date2j(1970, 1, 1)) * 86400));
+#endif
 
 #if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
                        tx = localtime(&utime);
@@ -703,19 +939,27 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
  * Also, month is one-based, _not_ zero-based.
  */
 int
-tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result)
+tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
 {
-
+#ifdef HAVE_INT64_TIMESTAMP
+       int             date;
+       int64   time;
+#else
        double          date,
                                time;
+#endif
 
        /* Julian day routines are not correct for negative Julian days */
        if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
                return -1;
 
        date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
-       time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec));
-       *result = (date * 86400 + time);
+       time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+#ifdef HAVE_INT64_TIMESTAMP
+       *result = ((date * INT64CONST(86400000000)) + time);
+#else
+       *result = ((date * 86400) + time);
+#endif
        if (tzp != NULL)
                *result = dt2local(*result, -(*tzp));
 
@@ -727,9 +971,13 @@ tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *result)
  * Convert a interval data type to a tm structure.
  */
 int
-interval2tm(Interval span, struct tm * tm, float8 *fsec)
+interval2tm(Interval span, struct tm * tm, fsec_t *fsec)
 {
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           time;
+#else
        double          time;
+#endif
 
        if (span.month != 0)
        {
@@ -743,45 +991,71 @@ interval2tm(Interval span, struct tm * tm, float8 *fsec)
                tm->tm_mon = 0;
        }
 
-#ifdef ROUND_ALL
-       time = JROUND(span.time);
-#else
        time = span.time;
-#endif
 
+#ifdef HAVE_INT64_TIMESTAMP
+       tm->tm_mday = (time / INT64CONST(86400000000));
+       time -= (tm->tm_mday * INT64CONST(86400000000));
+       tm->tm_hour = (time / INT64CONST(3600000000));
+       time -= (tm->tm_hour * INT64CONST(3600000000));
+       tm->tm_min = (time / INT64CONST(60000000));
+       time -= (tm->tm_min * INT64CONST(60000000));
+       tm->tm_sec = (time / INT64CONST(1000000));
+       *fsec = (time - (tm->tm_sec * INT64CONST(1000000)));
+#else
        TMODULO(time, tm->tm_mday, 86400e0);
        TMODULO(time, tm->tm_hour, 3600e0);
        TMODULO(time, tm->tm_min, 60e0);
        TMODULO(time, tm->tm_sec, 1e0);
        *fsec = time;
+#endif
 
        return 0;
 }      /* interval2tm() */
 
 int
-tm2interval(struct tm * tm, double fsec, Interval *span)
+tm2interval(struct tm * tm, fsec_t fsec, Interval *span)
 {
        span->month = ((tm->tm_year * 12) + tm->tm_mon);
+#ifdef HAVE_INT64_TIMESTAMP
+       span->time = ((((((((tm->tm_mday * INT64CONST(24))
+                                         + tm->tm_hour) * INT64CONST(60))
+                                       + tm->tm_min) * INT64CONST(60))
+                                 + tm->tm_sec) * INT64CONST(1000000)) + fsec);
+#else
        span->time = ((((((tm->tm_mday * 24.0)
                                          + tm->tm_hour) * 60.0)
                                        + tm->tm_min) * 60.0)
                                  + tm->tm_sec);
        span->time = JROUND(span->time + fsec);
+#endif
 
        return 0;
 }      /* tm2interval() */
 
+#ifdef HAVE_INT64_TIMESTAMP
+static int64
+time2t(const int hour, const int min, const int sec, const fsec_t fsec)
+{
+       return ((((((hour * 60) + min) * 60) + sec) * INT64CONST(1000000)) + fsec);
+}      /* time2t() */
+#else
 static double
-time2t(const int hour, const int min, const double sec)
+time2t(const int hour, const int min, const int sec, const fsec_t fsec)
 {
-       return (((hour * 60) + min) * 60) + sec;
+       return ((((hour * 60) + min) * 60) + sec + fsec);
 }      /* time2t() */
+#endif
 
 static Timestamp
 dt2local(Timestamp dt, int tz)
 {
+#ifdef HAVE_INT64_TIMESTAMP
+       dt -= (tz * INT64CONST(1000000));
+#else
        dt -= tz;
        dt = JROUND(dt);
+#endif
        return dt;
 }      /* dt2local() */
 
@@ -928,15 +1202,28 @@ timestamp_cmp(PG_FUNCTION_ARGS)
 static int
 interval_cmp_internal(Interval *interval1, Interval *interval2)
 {
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           span1,
+                               span2;
+#else
        double          span1,
                                span2;
+#endif
 
        span1 = interval1->time;
+       span2 = interval2->time;
+
+#ifdef HAVE_INT64_TIMESTAMP
+       if (interval1->month != 0)
+               span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+       if (interval2->month != 0)
+               span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
        if (interval1->month != 0)
                span1 += (interval1->month * (30.0 * 86400));
-       span2 = interval2->time;
        if (interval2->month != 0)
                span2 += (interval2->month * (30.0 * 86400));
+#endif
 
        return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
 }
@@ -1017,7 +1304,7 @@ interval_hash(PG_FUNCTION_ARGS)
         * sizeof(Interval), so that any garbage pad bytes in the structure
         * won't be included in the hash!
         */
-       return hash_any((unsigned char *) key, sizeof(double) + sizeof(int4));
+       return hash_any((unsigned char *) key, sizeof(key->time) + sizeof(key->month));
 }
 
 /* overlaps_timestamp() --- implements the SQL92 OVERLAPS operator.
@@ -1195,7 +1482,11 @@ timestamp_mi(PG_FUNCTION_ARGS)
                result->time = 0;
        }
        else
+#ifdef HAVE_INT64_TIMESTAMP
+               result->time = (dt1 - dt2);
+#else
                result->time = JROUND(dt1 - dt2);
+#endif
 
        result->month = 0;
 
@@ -1220,14 +1511,16 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
        Timestamp       result;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
+       {
                result = timestamp;
+       }
        else
        {
                if (span->month != 0)
                {
                        struct tm       tt,
                                           *tm = &tt;
-                       double          fsec;
+                       fsec_t          fsec;
 
                        if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
                        {
@@ -1262,12 +1555,7 @@ timestamp_pl_span(PG_FUNCTION_ARGS)
                        }
                }
 
-#ifdef ROUND_ALL
-               timestamp = JROUND(timestamp + span->time);
-#else
                timestamp += span->time;
-#endif
-
                result = timestamp;
        }
 
@@ -1316,7 +1604,7 @@ timestamptz_pl_span(PG_FUNCTION_ARGS)
                {
                        struct tm       tt,
                                           *tm = &tt;
-                       double          fsec;
+                       fsec_t          fsec;
 
                        if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) == 0)
                        {
@@ -1349,12 +1637,7 @@ timestamptz_pl_span(PG_FUNCTION_ARGS)
                        }
                }
 
-#ifdef ROUND_ALL
-               timestamp = JROUND(timestamp + span->time);
-#else
                timestamp += span->time;
-#endif
-
                result = timestamp;
        }
 
@@ -1398,17 +1681,29 @@ interval_smaller(PG_FUNCTION_ARGS)
        Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
        Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
        Interval   *result;
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           span1,
+                               span2;
+#else
        double          span1,
                                span2;
+#endif
 
        result = (Interval *) palloc(sizeof(Interval));
 
        span1 = interval1->time;
+       span2 = interval2->time;
+#ifdef HAVE_INT64_TIMESTAMP
+       if (interval1->month != 0)
+               span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+       if (interval2->month != 0)
+               span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
        if (interval1->month != 0)
                span1 += (interval1->month * (30.0 * 86400));
-       span2 = interval2->time;
        if (interval2->month != 0)
                span2 += (interval2->month * (30.0 * 86400));
+#endif
 
        if (span2 < span1)
        {
@@ -1430,17 +1725,29 @@ interval_larger(PG_FUNCTION_ARGS)
        Interval   *interval1 = PG_GETARG_INTERVAL_P(0);
        Interval   *interval2 = PG_GETARG_INTERVAL_P(1);
        Interval   *result;
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           span1,
+                               span2;
+#else
        double          span1,
                                span2;
+#endif
 
        result = (Interval *) palloc(sizeof(Interval));
 
        span1 = interval1->time;
+       span2 = interval2->time;
+#ifdef HAVE_INT64_TIMESTAMP
+       if (interval1->month != 0)
+               span1 += ((interval1->month * INT64CONST(30) * INT64CONST(86400000000)));
+       if (interval2->month != 0)
+               span2 += ((interval2->month * INT64CONST(30) * INT64CONST(86400000000)));
+#else
        if (interval1->month != 0)
                span1 += (interval1->month * (30.0 * 86400));
-       span2 = interval2->time;
        if (interval2->month != 0)
                span2 += (interval2->month * (30.0 * 86400));
+#endif
 
        if (span2 > span1)
        {
@@ -1466,7 +1773,11 @@ interval_pl(PG_FUNCTION_ARGS)
        result = (Interval *) palloc(sizeof(Interval));
 
        result->month = (span1->month + span2->month);
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = (span1->time + span2->time);
+#else
        result->time = JROUND(span1->time + span2->time);
+#endif
 
        PG_RETURN_INTERVAL_P(result);
 }
@@ -1481,7 +1792,11 @@ interval_mi(PG_FUNCTION_ARGS)
        result = (Interval *) palloc(sizeof(Interval));
 
        result->month = (span1->month - span2->month);
+#ifdef HAVE_INT64_TIMESTAMP
+       result->time = (span1->time - span2->time);
+#else
        result->time = JROUND(span1->time - span2->time);
+#endif
 
        PG_RETURN_INTERVAL_P(result);
 }
@@ -1492,15 +1807,26 @@ interval_mul(PG_FUNCTION_ARGS)
        Interval   *span1 = PG_GETARG_INTERVAL_P(0);
        float8          factor = PG_GETARG_FLOAT8(1);
        Interval   *result;
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           months;
+#else
        double          months;
+#endif
 
        result = (Interval *) palloc(sizeof(Interval));
 
        months = (span1->month * factor);
+#ifdef HAVE_INT64_TIMESTAMP
+       result->month = months;
+       result->time = (span1->time * factor);
+       result->time += ((months - result->month) * INT64CONST(30)
+                                        * INT64CONST(86400000000));
+#else
        result->month = rint(months);
        result->time = JROUND(span1->time * factor);
        /* evaluate fractional months as 30 days */
        result->time += JROUND((months - result->month) * 30 * 86400);
+#endif
 
        PG_RETURN_INTERVAL_P(result);
 }
@@ -1518,21 +1844,31 @@ mul_d_interval(PG_FUNCTION_ARGS)
 Datum
 interval_div(PG_FUNCTION_ARGS)
 {
-       Interval   *span1 = PG_GETARG_INTERVAL_P(0);
+       Interval   *span = PG_GETARG_INTERVAL_P(0);
        float8          factor = PG_GETARG_FLOAT8(1);
        Interval   *result;
+#ifndef HAVE_INT64_TIMESTAMP
        double          months;
+#endif
 
        result = (Interval *) palloc(sizeof(Interval));
 
        if (factor == 0.0)
                elog(ERROR, "interval_div: divide by 0.0 error");
 
-       months = (span1->month / factor);
+#ifdef HAVE_INT64_TIMESTAMP
+       result->month = (span->month / factor);
+       result->time = (span->time / factor);
+       /* evaluate fractional months as 30 days */
+       result->time += (((span->month - (result->month * factor))
+                                         * INT64CONST(30) * INT64CONST(86400000000)) / factor);
+#else
+       months = (span->month / factor);
        result->month = rint(months);
-       result->time = JROUND(span1->time / factor);
+       result->time = JROUND(span->time / factor);
        /* evaluate fractional months as 30 days */
        result->time += JROUND((months - result->month) * 30 * 86400);
+#endif
 
        PG_RETURN_INTERVAL_P(result);
 }
@@ -1641,7 +1977,7 @@ timestamp_age(PG_FUNCTION_ARGS)
        Timestamp       dt1 = PG_GETARG_TIMESTAMP(0);
        Timestamp       dt2 = PG_GETARG_TIMESTAMP(1);
        Interval   *result;
-       double          fsec,
+       fsec_t          fsec,
                                fsec1,
                                fsec2;
        struct tm       tt,
@@ -1750,7 +2086,7 @@ timestamptz_age(PG_FUNCTION_ARGS)
        TimestampTz dt1 = PG_GETARG_TIMESTAMP(0);
        TimestampTz dt2 = PG_GETARG_TIMESTAMP(1);
        Interval   *result;
-       double          fsec,
+       fsec_t          fsec,
                                fsec1,
                                fsec2;
        struct tm       tt,
@@ -2033,7 +2369,7 @@ timestamp_trunc(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowunits[MAXDATELEN + 1];
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
 
@@ -2079,11 +2415,17 @@ timestamp_trunc(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               fsec = ((fsec / 1000) * 1000);
+#else
                                fsec = rint(fsec * 1000) / 1000;
+#endif
                                break;
 
                        case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
                                fsec = rint(fsec * 1000000) / 1000000;
+#endif
                                break;
 
                        default:
@@ -2119,7 +2461,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowunits[MAXDATELEN + 1];
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn;
        struct tm       tt,
                           *tm = &tt;
@@ -2166,10 +2508,16 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               fsec = ((fsec / 1000) * 1000);
+#else
                                fsec = rint(fsec * 1000) / 1000;
+#endif
                                break;
                        case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
                                fsec = rint(fsec * 1000000) / 1000000;
+#endif
                                break;
 
                        default:
@@ -2206,7 +2554,7 @@ interval_trunc(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowunits[MAXDATELEN + 1];
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
 
@@ -2253,11 +2601,16 @@ interval_trunc(PG_FUNCTION_ARGS)
                                        break;
 
                                case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                                       fsec = ((fsec / 1000) * 1000);
+#else
                                        fsec = rint(fsec * 1000) / 1000;
+#endif
                                        break;
-
                                case DTK_MICROSEC:
+#ifndef HAVE_INT64_TIMESTAMP
                                        fsec = rint(fsec * 1000000) / 1000000;
+#endif
                                        break;
 
                                default:
@@ -2380,7 +2733,7 @@ timestamp_part(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowunits[MAXDATELEN + 1];
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
 
@@ -2410,15 +2763,27 @@ timestamp_part(PG_FUNCTION_ARGS)
                switch (val)
                {
                        case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
                                result = (tm->tm_sec + fsec) * 1000000;
+#endif
                                break;
 
                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
                                result = (tm->tm_sec + fsec) * 1000;
+#endif
                                break;
 
                        case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = (tm->tm_sec + (fsec / 1000000e0));
+#else
                                result = (tm->tm_sec + fsec);
+#endif
                                break;
 
                        case DTK_MINUTE:
@@ -2463,7 +2828,13 @@ timestamp_part(PG_FUNCTION_ARGS)
 
                        case DTK_JULIAN:
                                result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
-                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec) / 86400e0);
+#ifdef HAVE_INT64_TIMESTAMP
+                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+                                                       + tm->tm_sec + (fsec / 1000000e0)) / 86400e0);
+#else
+                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+                                                       + tm->tm_sec + fsec) / 86400e0);
+#endif
                                break;
 
                        case DTK_TZ:
@@ -2479,7 +2850,7 @@ timestamp_part(PG_FUNCTION_ARGS)
                switch (val)
                {
                        case DTK_EPOCH:
-                               result = timestamp - SetEpochTimestamp();
+                               result = ((timestamp - SetEpochTimestamp()) / 1000000e0);
                                break;
 
                        case DTK_DOW:
@@ -2529,7 +2900,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
                           *lp,
                                lowunits[MAXDATELEN + 1];
        double          dummy;
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn;
        struct tm       tt,
                           *tm = &tt;
@@ -2574,15 +2945,27 @@ timestamptz_part(PG_FUNCTION_ARGS)
                                break;
 
                        case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
                                result = (tm->tm_sec + fsec) * 1000000;
+#endif
                                break;
 
                        case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
                                result = (tm->tm_sec + fsec) * 1000;
+#endif
                                break;
 
                        case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = (tm->tm_sec + (fsec / 1000000e0));
+#else
                                result = (tm->tm_sec + fsec);
+#endif
                                break;
 
                        case DTK_MINUTE:
@@ -2627,7 +3010,13 @@ timestamptz_part(PG_FUNCTION_ARGS)
 
                        case DTK_JULIAN:
                                result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
-                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec) / 86400e0);
+#ifdef HAVE_INT64_TIMESTAMP
+                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+                                                       + tm->tm_sec + (fsec / 1000000e0)) / 86400e0);
+#else
+                               result += (((((tm->tm_hour * 60) + tm->tm_min) * 60)
+                                                       + tm->tm_sec + fsec) / 86400e0);
+#endif
                                break;
 
                        default:
@@ -2641,7 +3030,11 @@ timestamptz_part(PG_FUNCTION_ARGS)
                switch (val)
                {
                        case DTK_EPOCH:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((timestamp - SetEpochTimestamp()) / 100000e0);
+#else
                                result = timestamp - SetEpochTimestamp();
+#endif
                                break;
 
                        case DTK_DOW:
@@ -2689,7 +3082,7 @@ interval_part(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowunits[MAXDATELEN + 1];
-       double          fsec;
+       fsec_t          fsec;
        struct tm       tt,
                           *tm = &tt;
 
@@ -2713,17 +3106,29 @@ interval_part(PG_FUNCTION_ARGS)
                {
                        switch (val)
                        {
-                               case DTK_MICROSEC:
-                                       result = ((tm->tm_sec + fsec) * 1000000);
-                                       break;
+                       case DTK_MICROSEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000000e0) + fsec);
+#else
+                               result = (tm->tm_sec + fsec) * 1000000;
+#endif
+                               break;
 
-                               case DTK_MILLISEC:
-                                       result = ((tm->tm_sec + fsec) * 1000);
-                                       break;
+                       case DTK_MILLISEC:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = ((tm->tm_sec * 1000e0) + (fsec / 1000e0));
+#else
+                               result = (tm->tm_sec + fsec) * 1000;
+#endif
+                               break;
 
-                               case DTK_SECOND:
-                                       result = (tm->tm_sec + fsec);
-                                       break;
+                       case DTK_SECOND:
+#ifdef HAVE_INT64_TIMESTAMP
+                               result = (tm->tm_sec + (fsec / 1000000e0));
+#else
+                               result = (tm->tm_sec + fsec);
+#endif
+                               break;
 
                                case DTK_MINUTE:
                                        result = tm->tm_min;
@@ -2778,11 +3183,15 @@ interval_part(PG_FUNCTION_ARGS)
        }
        else if ((type == RESERV) && (val == DTK_EPOCH))
        {
+#ifdef HAVE_INT64_TIMESTAMP
+               result = (interval->time / 1000000e0);
+#else
                result = interval->time;
+#endif
                if (interval->month != 0)
                {
                        result += ((365.25 * 86400) * (interval->month / 12));
-                       result += ((30 * 86400) * (interval->month % 12));
+                       result += ((30.0 * 86400) * (interval->month % 12));
                }
        }
        else
@@ -2799,6 +3208,8 @@ interval_part(PG_FUNCTION_ARGS)
 
 /* timestamp_zone()
  * Encode timestamp type with specified time zone.
+ * Returns timestamp with time zone, with the input
+ *  rotated from local time to the specified zone.
  */
 Datum
 timestamp_zone(PG_FUNCTION_ARGS)
@@ -2832,8 +3243,9 @@ timestamp_zone(PG_FUNCTION_ARGS)
 
        if ((type == TZ) || (type == DTZ))
        {
-               tz = val * 60;
-               result = timestamp - tz;
+               tz = -(val * 60);
+
+               result = dt2local(timestamp, tz);
        }
        else
        {
@@ -2846,7 +3258,6 @@ timestamp_zone(PG_FUNCTION_ARGS)
 
 /* timestamp_izone()
  * Encode timestamp type with specified time interval as time zone.
- * Require ISO-formatted result, since character-string time zone is not available.
  */
 Datum
 timestamp_izone(PG_FUNCTION_ARGS)
@@ -2864,8 +3275,13 @@ timestamp_izone(PG_FUNCTION_ARGS)
                         DatumGetCString(DirectFunctionCall1(interval_out,
                                                                                                 PointerGetDatum(zone))));
 
-       tz = -(zone->time);
-       result = timestamp - tz;
+#ifdef HAVE_INT64_TIMESTAMP
+       tz = (zone->time / INT64CONST(1000000));
+#else
+       tz = (zone->time);
+#endif
+
+       result = dt2local(timestamp, tz);
 
        PG_RETURN_TIMESTAMPTZ(result);
 }      /* timestamp_izone() */
@@ -2880,7 +3296,7 @@ timestamp_timestamptz(PG_FUNCTION_ARGS)
        TimestampTz result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        int                     tz;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
@@ -2909,7 +3325,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
        Timestamp       result;
        struct tm       tt,
                           *tm = &tt;
-       double          fsec;
+       fsec_t          fsec;
        char       *tzn;
        int                     tz;
 
@@ -2928,15 +3344,16 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
 }
 
 /* timestamptz_zone()
- * Encode timestamp with time zone type with specified time zone.
+ * Evaluate timestamp with time zone type at the specified time zone.
+ * Returns a timestamp without time zone.
  */
 Datum
 timestamptz_zone(PG_FUNCTION_ARGS)
 {
        text       *zone = PG_GETARG_TEXT_P(0);
        TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
-       text       *result;
-       TimestampTz dt;
+       Timestamp       result;
+
        int                     tz;
        int                     type,
                                val;
@@ -2944,13 +3361,6 @@ timestamptz_zone(PG_FUNCTION_ARGS)
        char       *up,
                           *lp,
                                lowzone[MAXDATELEN + 1];
-       char       *tzn,
-                               upzone[MAXDATELEN + 1];
-       double          fsec;
-       struct tm       tt,
-                          *tm = &tt;
-       char            buf[MAXDATELEN + 1];
-       int                     len;
 
        if (VARSIZE(zone) - VARHDRSZ > MAXDATELEN)
                elog(ERROR, "Time zone '%s' not recognized",
@@ -2965,86 +3375,50 @@ timestamptz_zone(PG_FUNCTION_ARGS)
        type = DecodeSpecial(0, lowzone, &val);
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
-               PG_RETURN_TEXT_P(pstrdup(""));
+               PG_RETURN_NULL();
 
        if ((type == TZ) || (type == DTZ))
        {
-               tm->tm_isdst = ((type == DTZ) ? 1 : 0);
                tz = val * 60;
 
-               dt = dt2local(timestamp, tz);
-
-               if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
-                       elog(ERROR, "Unable to decode TIMESTAMP WITH TIME ZONE"
-                                "\n\ttimestamptz_zone() internal coding error");
-
-               up = upzone;
-               lp = lowzone;
-               for (i = 0; *lp != '\0'; i++)
-                       *up++ = toupper((unsigned char) *lp++);
-               *up = '\0';
-
-               tzn = upzone;
-               EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
-
-               len = (strlen(buf) + VARHDRSZ);
-
-               result = palloc(len);
-
-               VARATT_SIZEP(result) = len;
-               memmove(VARDATA(result), buf, (len - VARHDRSZ));
+               result = dt2local(timestamp, tz);
        }
        else
        {
                elog(ERROR, "Time zone '%s' not recognized", lowzone);
-               PG_RETURN_TEXT_P(pstrdup(""));
+               PG_RETURN_NULL();
        }
 
-       PG_RETURN_TEXT_P(result);
+       PG_RETURN_TIMESTAMP(result);
 }      /* timestamptz_zone() */
 
 /* timestamptz_izone()
  * Encode timestamp with time zone type with specified time interval as time zone.
- * Require ISO-formatted result, since character-string time zone is not available.
+ * Returns a timestamp without time zone.
  */
 Datum
 timestamptz_izone(PG_FUNCTION_ARGS)
 {
        Interval   *zone = PG_GETARG_INTERVAL_P(0);
        TimestampTz timestamp = PG_GETARG_TIMESTAMP(1);
-       text       *result;
-       TimestampTz dt;
+       Timestamp       result;
        int                     tz;
-       char       *tzn = "";
-       double          fsec;
-       struct tm       tt,
-                          *tm = &tt;
-       char            buf[MAXDATELEN + 1];
-       int                     len;
 
        if (TIMESTAMP_NOT_FINITE(timestamp))
-               PG_RETURN_TEXT_P(pstrdup(""));
+               PG_RETURN_NULL();
 
        if (zone->month != 0)
                elog(ERROR, "INTERVAL time zone '%s' not legal (month specified)",
                         DatumGetCString(DirectFunctionCall1(interval_out,
                                                                                                 PointerGetDatum(zone))));
 
-       tm->tm_isdst = -1;
+#ifdef HAVE_INT64_TIMESTAMP
+       tz = -(zone->time / INT64CONST(1000000));
+#else
        tz = -(zone->time);
+#endif
 
-       dt = dt2local(timestamp, tz);
-
-       if (timestamp2tm(dt, NULL, tm, &fsec, NULL) != 0)
-               elog(ERROR, "Unable to decode TIMESTAMP WITH TIME ZONE"
-                        "\n\ttimestamptz_izone() internal coding error");
-
-       EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
-       len = (strlen(buf) + VARHDRSZ);
+       result = dt2local(timestamp, tz);
 
-       result = palloc(len);
-       VARATT_SIZEP(result) = len;
-       memmove(VARDATA(result), buf, (len - VARHDRSZ));
-
-       PG_RETURN_TEXT_P(result);
+       PG_RETURN_TIMESTAMP(result);
 }      /* timestamptz_izone() */
index aba1d146cbd271be6c6debd4229cff510c5c5593..1dddc7aa11d1f4677204b904936676eca3abc144 100644 (file)
@@ -302,6 +302,10 @@ typedef unsigned long int uint64;
 
 #endif /* not HAVE_LONG_INT_64 and not HAVE_LONG_LONG_INT_64 */
 
+#if defined(USE_INTEGER_DATETIMES) && !defined(INT64_IS_BUSTED)
+#define HAVE_INT64_TIMESTAMP
+#endif
+
 /* sig_atomic_t is required by ANSI C, but may be missing on old platforms */
 #ifndef HAVE_SIG_ATOMIC_T
 typedef int sig_atomic_t;
index 42238ca0b46578ec3a368b20b2f24e625e292241..42b850a438c040e5d0649e1f3decd5a171abdf87 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200204201
+#define CATALOG_VERSION_NO     200204211
 
 #endif
index be3e30ef0423b52dd69a14e8bacd7d8418a8cd96..87e459471386679ce7183200e3e2c1afae6c606c 100644 (file)
@@ -22,7 +22,7 @@
 
 
 /* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION     71
+#define PG_CONTROL_VERSION     72
 
 /*
  * Body of CheckPoint XLOG records.  This is declared here because we keep
@@ -106,7 +106,15 @@ typedef struct ControlFileData
         */
        uint32          blcksz;                 /* block size for this DB */
        uint32          relseg_size;    /* blocks per segment of large relation */
+
+       uint32          nameDataLen;    /* catalog name field width */
+       uint32          funcMaxArgs;    /* maximum number of function arguments */
+
+       /* flag indicating internal format of timestamp, interval, time */
+       uint32          enableIntTimes; /* int64 storage enabled? */
+
        /* active locales --- "C" if compiled without USE_LOCALE: */
+       uint32          localeBuflen;
        char            lc_collate[LOCALE_NAME_BUFLEN];
        char            lc_ctype[LOCALE_NAME_BUFLEN];
 } ControlFileData;
index 674ba2ffe2cee6fe2023bc2badbcf99a65f0a703..848a39d5ecf52616c51a1d02ac90a98be48df4d7 100644 (file)
@@ -476,6 +476,8 @@ DATA(insert OID = 1068 ( ">"           PGNSP PGUID 0 b t f 1043 1043        16 1066 1067  0 0
 DATA(insert OID = 1069 ( ">="     PGNSP PGUID 0 b t f 1043 1043        16 1067 1066  0 0 0 0 varcharge scalargtsel scalargtjoinsel ));
 
 /* date operators */
+DATA(insert OID = 1076 ( "+"      PGNSP PGUID 0 b t f  1082    1186 1114 0 0 0 0 0 0 date_pl_interval - - ));
+DATA(insert OID = 1077 ( "-"      PGNSP PGUID 0 b t f  1082    1186 1114 0 0 0 0 0 0 date_mi_interval - - ));
 DATA(insert OID = 1093 ( "="      PGNSP PGUID 0 b t t  1082    1082   16 1093 1094 1095 1095 1095 1097 date_eq eqsel eqjoinsel ));
 DATA(insert OID = 1094 ( "<>"     PGNSP PGUID 0 b t f  1082    1082   16 1094 1093  0 0 0 0 date_ne neqsel neqjoinsel ));
 DATA(insert OID = 1095 ( "<"      PGNSP PGUID 0 b t f  1082    1082   16 1097 1098  0 0 0 0 date_lt scalarltsel scalarltjoinsel ));
index 38b829b3797ef660fb8cc8addbc34a344a377766..7343a1c7ded098e041257bf143c5e0792191ebb0 100644 (file)
@@ -1280,7 +1280,7 @@ DESCR("convert timetz to text");
 
 /* OIDS 1000 - 1999 */
 
-DATA(insert OID = 1026 (  timezone                PGNSP PGUID 12 f t f t f s 2 25 "1186 1184" 100 0 0 100      timestamptz_izone - _null_ ));
+DATA(insert OID = 1026 (  timezone                PGNSP PGUID 12 f t f t f s 2 1186 "1186 1184" 100 0 0 100    timestamptz_izone - _null_ ));
 DESCR("time zone");
 
 DATA(insert OID = 1029 (  nullvalue               PGNSP PGUID 12 f t f f f i 1 16 "0" 100 0 0 100      nullvalue - _null_ ));
@@ -1414,8 +1414,8 @@ DATA(insert OID = 1156 (  timestamptz_ge   PGNSP PGUID 12 f t f t f i 2 16 "1184
 DESCR("greater-than-or-equal");
 DATA(insert OID = 1157 (  timestamptz_gt   PGNSP PGUID 12 f t f t f i 2 16 "1184 1184" 100 0 0 100     timestamp_gt - _null_ ));
 DESCR("greater-than");
-DATA(insert OID = 1159 (  timezone                PGNSP PGUID 12 f t f t f s 2 25 "25 1184" 100 0 0 100  timestamptz_zone - _null_ ));
-DESCR("time zone");
+DATA(insert OID = 1159 (  timezone                PGNSP PGUID 12 f t f t f s 2 1114 "25 1184" 100 0 0 100  timestamptz_zone - _null_ ));
+DESCR("timestamp at a specified time zone");
 
 DATA(insert OID = 1160 (  interval_in     PGNSP PGUID 12 f t f t f s 1 1186 "0" 100 0 0 100  interval_in - _null_ ));
 DESCR("(internal)");
@@ -1710,13 +1710,13 @@ DATA(insert OID = 1383 (  date_part    PGNSP PGUID 14 f t f t f s 2  701 "25 703
 DESCR("extract field from reltime");
 DATA(insert OID = 1384 (  date_part    PGNSP PGUID 14 f t f t f i 2  701 "25 1082" 100 0 0 100 "select date_part($1, cast($2 as timestamp without time zone))" - _null_ ));
 DESCR("extract field from date");
-DATA(insert OID = 1385 (  date_part    PGNSP PGUID 14 f t f t f i 2  701 "25 1083" 100 0 0 100 "select date_part($1, cast($2 as time with time zone))" - _null_ ));
+DATA(insert OID = 1385 (  date_part       PGNSP PGUID 12 f t f t f i 2  701 "25 1083" 100 0 0 100  time_part - _null_ ));
 DESCR("extract field from time");
 DATA(insert OID = 1386 (  age             PGNSP PGUID 14 f t f t f s 1 1186 "1184" 100 0 0 100  "select age(cast(current_date as timestamp with time zone), $1)" - _null_ ));
 DESCR("date difference from today preserving months and years");
 
-DATA(insert OID = 1388 (  timetz                  PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100  timestamptz_timetz - _null_ ));
-DESCR("convert timestamp to timetz");
+DATA(insert OID = 1388 (  timetz          PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100  timestamptz_timetz - _null_ ));
+DESCR("convert timestamptz to timetz");
 
 DATA(insert OID = 1389 (  isfinite        PGNSP PGUID 12 f t f t f i 1 16 "1184" 100 0 0 100  timestamp_finite - _null_ ));
 DESCR("boolean test");
@@ -2769,6 +2769,8 @@ DESCR("return position of substring");
 DATA(insert OID = 2015 (  btrim                           PGNSP PGUID 12 f t f t f i 2 17 "17 17" 100 0 0 100  byteatrim - _null_ ));
 DESCR("trim both ends of string");
 
+DATA(insert OID = 2019 (  time                         PGNSP PGUID 12 f t f t f s 1 1083 "1184" 100 0 0 100  timestamptz_time - _null_ ));
+DESCR("convert timestamptz to time");
 DATA(insert OID = 2020 (  date_trunc           PGNSP PGUID 12 f t f t f i 2 1114 "25 1114" 100 0 0 100  timestamp_trunc - _null_ ));
 DESCR("truncate timestamp to specified units");
 DATA(insert OID = 2021 (  date_part                    PGNSP PGUID 12 f t f t f i 2  701 "25 1114" 100 0 0 100  timestamp_part - _null_ ));
@@ -2801,9 +2803,9 @@ DATA(insert OID = 2035 (  timestamp_smaller PGNSP PGUID 12 f t f t f i 2 1114 "1
 DESCR("smaller of two");
 DATA(insert OID = 2036 (  timestamp_larger     PGNSP PGUID 12 f t f t f i 2 1114 "1114 1114" 100 0 0 100  timestamp_larger - _null_ ));
 DESCR("larger of two");
-DATA(insert OID = 2037 (  timetz                       PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100  timetz_zone - _null_ ));
+DATA(insert OID = 2037 (  timezone                     PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100  timetz_zone - _null_ ));
 DESCR("time with time zone");
-DATA(insert OID = 2038 (  timetz                       PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100  timetz_izone - _null_ ));
+DATA(insert OID = 2038 (  timezone                     PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100  timetz_izone - _null_ ));
 DESCR("time with time zone");
 DATA(insert OID = 2041 ( overlaps                      PGNSP PGUID 12 f t f f f i 4 16 "1114 1114 1114 1114" 100 0 0 100  overlaps_timestamp - _null_ ));
 DESCR("SQL92 interval comparison");
@@ -2843,10 +2845,15 @@ DATA(insert OID = 2058 (  age                           PGNSP PGUID 12 f t f t f i 2 1186 "1114 1114" 1
 DESCR("date difference preserving months and years");
 DATA(insert OID = 2059 (  age                          PGNSP PGUID 14 f t f t f s 1 1186 "1114" 100 0 0 100  "select age(cast(current_date as timestamp without time zone), $1)" - _null_ ));
 DESCR("date difference from today preserving months and years");
+
 DATA(insert OID = 2069 (  timezone                     PGNSP PGUID 12 f t f t f s 2 1184 "25 1114" 100 0 0 100  timestamp_zone - _null_ ));
-DESCR("time zone");
+DESCR("timestamp at a specified time zone");
 DATA(insert OID = 2070 (  timezone                     PGNSP PGUID 12 f t f t f s 2 1184 "1186 1114" 100 0 0 100  timestamp_izone - _null_ ));
 DESCR("time zone");
+DATA(insert OID = 2071 (  date_pl_interval     PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100  "select cast($1 as timestamp without time zone) + $2;" - _null_ ));
+DESCR("add");
+DATA(insert OID = 2072 (  date_mi_interval     PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100  "select cast($1 as timestamp without time zone) - $2;" - _null_ ));
+DESCR("subtract");
 
 /* Aggregates (moved here from pg_aggregate for 7.3) */
 
index d61627fb5eebce7d8402ee022ba95c8d3b61107e..e37dab65dee466ee3de3594e888b4d0e0a5921dd 100644 (file)
@@ -33,6 +33,9 @@
 /* A canonical string containing the version number, platform, and C compiler */
 #undef PG_VERSION_STR
 
+/* Set to 1 if you want 64-bit integer timestamp and interval support (--enable-integer-datetimes) */
+#undef USE_INTEGER_DATETIMES
+
 /* Set to 1 if you want cyrillic recode (--enable-recode) */
 #undef CYR_RECODE
 
index a7c82424f10afb65bdb68fda4c78632646625b61..97f771fbd4039a9914358337597f8b32f0630d71 100644 (file)
 #ifndef DATE_H
 #define DATE_H
 
+#include "c.h"
 #include "fmgr.h"
 
 
 typedef int32 DateADT;
 
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int64 TimeADT;
+#else
 typedef float8 TimeADT;
+#endif
 
 typedef struct
 {
-       double          time;                   /* all time units other than months and
-                                                                * years */
-       int32           zone;                   /* numeric time zone, in seconds */
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           time;   /* all time units other than months and years */
+#else
+       double          time;   /* all time units other than months and years */
+#endif
+       int32           zone;   /* numeric time zone, in seconds */
 } TimeTzADT;
 
+#ifdef HAVE_INT64_TIMESTAMP
+#define MAX_TIME_PRECISION 6
+#else
+#define MAX_TIME_PRECISION 13
+#endif
+
 /*
  * Macros for fmgr-callable functions.
  *
@@ -90,6 +104,7 @@ extern Datum time_larger(PG_FUNCTION_ARGS);
 extern Datum time_smaller(PG_FUNCTION_ARGS);
 extern Datum time_mi_time(PG_FUNCTION_ARGS);
 extern Datum timestamp_time(PG_FUNCTION_ARGS);
+extern Datum timestamptz_time(PG_FUNCTION_ARGS);
 extern Datum time_interval(PG_FUNCTION_ARGS);
 extern Datum interval_time(PG_FUNCTION_ARGS);
 extern Datum text_time(PG_FUNCTION_ARGS);
@@ -97,6 +112,7 @@ extern Datum time_text(PG_FUNCTION_ARGS);
 extern Datum time_pl_interval(PG_FUNCTION_ARGS);
 extern Datum time_mi_interval(PG_FUNCTION_ARGS);
 extern Datum interval_pl_time(PG_FUNCTION_ARGS);
+extern Datum time_part(PG_FUNCTION_ARGS);
 
 extern Datum timetz_in(PG_FUNCTION_ARGS);
 extern Datum timetz_out(PG_FUNCTION_ARGS);
index 4bf13c3b8665370c198497f88442beb42071b15f..676959dc251eb3b5afad54b21630ae5d04ce7dcc 100644 (file)
@@ -198,15 +198,26 @@ typedef struct
 
 /* TMODULO()
  * Macro to replace modf(), which is broken on some platforms.
+ * t = input and remainder
+ * q = integer part
+ * u = divisor
  */
+#ifdef HAVE_INT64_TIMESTAMP
+#define TMODULO(t,q,u) \
+do { \
+       q = (t / u); \
+       if (q != 0) t -= (q * u); \
+} while(0)
+#else
 #define TMODULO(t,q,u) \
 do { \
        q = ((t < 0)? ceil(t / u): floor(t / u)); \
-       if (q != 0) \
-               t -= rint(q * u); \
+       if (q != 0) t -= rint(q * u); \
 } while(0)
+#endif
 
-#ifdef __CYGWIN__
+/* Global variable holding time zone information. */
+#if defined(__CYGWIN__) || defined(N_PLAT_NLM)
 #define TIMEZONE_GLOBAL _timezone
 #else
 #define TIMEZONE_GLOBAL timezone
@@ -250,7 +261,7 @@ extern int  day_tab[2][13];
 
 
 extern void GetCurrentTime(struct tm * tm);
-extern void GetCurrentTimeUsec(struct tm * tm, double *fsec);
+extern void GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec);
 extern void j2date(int jd, int *year, int *month, int *day);
 extern int     date2j(int year, int month, int day);
 
@@ -259,22 +270,22 @@ extern int ParseDateTime(char *timestr, char *lowstr,
                          int maxfields, int *numfields);
 extern int DecodeDateTime(char **field, int *ftype,
                           int nf, int *dtype,
-                          struct tm * tm, double *fsec, int *tzp);
+                          struct tm * tm, fsec_t *fsec, int *tzp);
 
 extern int DecodeTimeOnly(char **field, int *ftype,
                           int nf, int *dtype,
-                          struct tm * tm, double *fsec, int *tzp);
+                          struct tm * tm, fsec_t *fsec, int *tzp);
 
-extern int DecodeDateDelta(char **field, int *ftype,
+extern int DecodeInterval(char **field, int *ftype,
                                int nf, int *dtype,
-                               struct tm * tm, double *fsec);
+                               struct tm * tm, fsec_t *fsec);
 
 extern int     DetermineLocalTimeZone(struct tm * tm);
 
 extern int     EncodeDateOnly(struct tm * tm, int style, char *str);
-extern int     EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str);
-extern int     EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str);
-extern int     EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str);
+extern int     EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str);
+extern int     EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str);
+extern int     EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
 
 extern int     DecodeSpecial(int field, char *lowtoken, int *val);
 extern int     DecodeUnits(int field, char *lowtoken, int *val);
index dcaa5de2fe5c4063305601851bc5daad49cc0d9a..0cc712b1840c49486144bfeb2c880a9ca03f5f73 100644 (file)
  *     is not currently supported, then please try to make it so, then post
  *     patches to the postgresql.org hackers mailing list.
  *
- * This code was written for and originally appeared in the contrib
- *     directory as a user-defined type.
- * - thomas 1998-06-08
- *
  *-------------------------------------------------------------------------
  */
 #ifndef INT8_H
 #define INT8_H
 
+#include "c.h"
 #include "fmgr.h"
 
+/* this should be set in pg_config.h, but just in case it wasn't: */
+#ifndef INT64_FORMAT
+#warning "Broken pg_config.h should have defined INT64_FORMAT"
+#define INT64_FORMAT "%ld"
+#endif
+
+#ifdef HAVE_LL_CONSTANTS
+#define INT64CONST(x)  ((int64) x##LL)
+#else
+#define INT64CONST(x)  ((int64) x)
+#endif
 
 extern Datum int8in(PG_FUNCTION_ARGS);
 extern Datum int8out(PG_FUNCTION_ARGS);
index 39db8274ebf045bccc1fba4e9100d1547849337b..5f83c557247d3deb2ca252a8472d6b7c3cea4daa 100644 (file)
 #include <limits.h>
 #include <float.h>
 
+#include "c.h"
 #include "fmgr.h"
-
+#ifdef HAVE_INT64_TIMESTAMP
+#include "utils/int8.h"
+#endif
 
 /*
  * Timestamp represents absolute time.
  *     consisting of a beginning and ending time, not a time span - thomas 97/03/20
  */
 
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int64 Timestamp;
+typedef int64 TimestampTz;
+#else
 typedef double Timestamp;
-
 typedef double TimestampTz;
+#endif
 
 typedef struct
 {
-       double          time;                   /* all time units other than months and
-                                                                * years */
-       int32           month;                  /* months and years, after time for
-                                                                * alignment */
+#ifdef HAVE_INT64_TIMESTAMP
+       int64           time;   /* all time units other than months and years */
+#else
+       double          time;   /* all time units other than months and years */
+#endif
+       int32           month;  /* months and years, after time for alignment */
 } Interval;
 
 
@@ -50,6 +59,27 @@ typedef struct
  * For Timestamp, we make use of the same support routines as for float8.
  * Therefore Timestamp is pass-by-reference if and only if float8 is!
  */
+#ifdef HAVE_INT64_TIMESTAMP
+#define DatumGetTimestamp(X)  ((Timestamp) DatumGetInt64(X))
+#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X))
+#define DatumGetIntervalP(X)  ((Interval *) DatumGetPointer(X))
+
+#define TimestampGetDatum(X) Int64GetDatum(X)
+#define TimestampTzGetDatum(X) Int64GetDatum(X)
+#define IntervalPGetDatum(X) PointerGetDatum(X)
+
+#define PG_GETARG_TIMESTAMP(n) PG_GETARG_INT64(n)
+#define PG_GETARG_TIMESTAMPTZ(n) PG_GETARG_INT64(n)
+#define PG_GETARG_INTERVAL_P(n) DatumGetIntervalP(PG_GETARG_DATUM(n))
+
+#define PG_RETURN_TIMESTAMP(x) PG_RETURN_INT64(x)
+#define PG_RETURN_TIMESTAMPTZ(x) PG_RETURN_INT64(x)
+#define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x)
+
+#define DT_NOBEGIN             (-INT64CONST(0x7fffffffffffffff) - 1)
+#define DT_NOEND               (INT64CONST(0x7fffffffffffffff))
+
+#else
 #define DatumGetTimestamp(X)  ((Timestamp) DatumGetFloat8(X))
 #define DatumGetTimestampTz(X) ((TimestampTz) DatumGetFloat8(X))
 #define DatumGetIntervalP(X)  ((Interval *) DatumGetPointer(X))
@@ -66,7 +96,6 @@ typedef struct
 #define PG_RETURN_TIMESTAMPTZ(x) return TimestampTzGetDatum(x)
 #define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x)
 
-
 #ifdef HUGE_VAL
 #define DT_NOBEGIN             (-HUGE_VAL)
 #define DT_NOEND               (HUGE_VAL)
@@ -74,6 +103,7 @@ typedef struct
 #define DT_NOBEGIN             (-DBL_MAX)
 #define DT_NOEND               (DBL_MAX)
 #endif
+#endif
 
 #define TIMESTAMP_NOBEGIN(j)   do {j = DT_NOBEGIN;} while (0)
 #define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN)
@@ -83,8 +113,21 @@ typedef struct
 
 #define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j))
 
+
+#define MAX_TIMESTAMP_PRECISION 6
+#define MAX_INTERVAL_PRECISION 6
+
+#ifdef HAVE_INT64_TIMESTAMP
+typedef int32 fsec_t;
+
+#define SECONDS_TO_TIMESTAMP(x) (INT64CONST(x000000))
+#else
+typedef double fsec_t;
+
+#define SECONDS_TO_TIMESTAMP(x) (xe0)
 #define TIME_PREC_INV 1000000.0
 #define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV)
+#endif
 
 
 /*
@@ -167,13 +210,13 @@ extern Datum now(PG_FUNCTION_ARGS);
 
 /* Internal routines (not fmgr-callable) */
 
-extern int     tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt);
+extern int     tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
 extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm,
-                        double *fsec, char **tzn);
-extern void dt2time(Timestamp dt, int *hour, int *min, double *sec);
+                        fsec_t *fsec, char **tzn);
+extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec);
 
-extern int     interval2tm(Interval span, struct tm * tm, float8 *fsec);
-extern int     tm2interval(struct tm * tm, double fsec, Interval *span);
+extern int     interval2tm(Interval span, struct tm * tm, fsec_t *fsec);
+extern int     tm2interval(struct tm * tm, fsec_t fsec, Interval *span);
 
 extern Timestamp SetEpochTimestamp(void);
 extern void GetEpochTime(struct tm * tm);