diff options
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 716 |
1 files changed, 545 insertions, 171 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 5fbdc5b8d89..7637ccf150b 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.65 2002/03/09 17:35:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.66 2002/04/21 19:48:13 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,11 @@ #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() */ |