diff options
Diffstat (limited to 'src/backend/utils/adt')
| -rw-r--r-- | src/backend/utils/adt/date.c | 510 | ||||
| -rw-r--r-- | src/backend/utils/adt/datetime.c | 556 | ||||
| -rw-r--r-- | src/backend/utils/adt/formatting.c | 21 | ||||
| -rw-r--r-- | src/backend/utils/adt/int8.c | 3 | ||||
| -rw-r--r-- | src/backend/utils/adt/nabstime.c | 96 | ||||
| -rw-r--r-- | src/backend/utils/adt/selfuncs.c | 19 | ||||
| -rw-r--r-- | src/backend/utils/adt/timestamp.c | 716 |
7 files changed, 1460 insertions, 461 deletions
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 2c261198b4..ab8403cc31 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.65 2002/03/09 17:35:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.66 2002/04/21 19:48:12 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,10 @@ #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); diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 1dd540abb7..1a908d9d6b 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.88 2002/02/25 16:17:04 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.89 2002/04/21 19:48:12 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -28,12 +28,12 @@ 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 diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 231bad2ca6..7d28d16001 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * formatting.c * - * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.52 2002/04/03 05:39:29 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.53 2002/04/21 19:48:12 thomas Exp $ * * * Portions Copyright (c) 1999-2000, PostgreSQL Global Development Group @@ -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 /* -------------------------------------------------------------- */ diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 6a5eb15d74..685d5e3439 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.37 2002/02/23 01:01:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.38 2002/04/21 19:48:12 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -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 diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 299a082fac..651ca00d78 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.92 2002/03/06 06:10:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.93 2002/04/21 19:48:12 thomas Exp $ * * NOTES * @@ -76,21 +76,6 @@ 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) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 3b1af8df5e..d045705917 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.108 2002/04/16 23:08:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.109 2002/04/21 19:48:13 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -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 } } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 5fbdc5b8d8..7637ccf150 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() */ |
