diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 2c261198b45c998ebae5ed4411ed42ebd8be80bd..ab8403cc3183b38b162120f99a8105d767ec32f1 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 1dd540abb7f13457ec31ca1a933c9a28894bf761..1a908d9d6b7d15801f1e383b8c964f659322b942 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 231bad2ca6dd2c976b9759b7d6edce148075bcde..7d28d16001f29aa80420b6a97aaa04e5bf951c0f 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 6a5eb15d749b5efaf76f366bcf52b0ebc719073d..685d5e34398aa19577d875bc9502b0ac61480990 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 299a082facb308e5ef0cd8baf80767576c0a7aca..651ca00d78ef2f33fa13508afbcc5fd4649bf297 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 3b1af8df5e180e4157b0c95c6ea80cbce91aa73e..d045705917dfbf857f8429ae476dd8366084f0a0 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 5fbdc5b8d89e57663448c7beb097159d00f2eaf1..7637ccf150b40de7f42e9b83b66e68cf4855e62a 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() */ diff --git a/src/include/c.h b/src/include/c.h index 29de386087901b4ec3f187ab5fcb7b0873af0b9e..52637717f58a7d11fd7c6546e772187ebc130f39 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: c.h,v 1.115 2002/03/29 17:32:55 petere Exp $ + * $Id: c.h,v 1.116 2002/04/21 19:48:18 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -302,6 +302,10 @@ typedef unsigned long int uint64; #endif /* not HAVE_LONG_INT_64 and not HAVE_LONG_LONG_INT_64 */ +#if defined(USE_INTEGER_DATETIMES) && !defined(INT64_IS_BUSTED) +#define HAVE_INT64_TIMESTAMP +#endif + /* sig_atomic_t is required by ANSI C, but may be missing on old platforms */ #ifndef HAVE_SIG_ATOMIC_T typedef int sig_atomic_t; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 299cef2bb40d8ed8db9162ae6cf61d91f482d03d..00a00bf1b03ad69c1eaea6e9c08a1e028bc668d9 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.121 2002/04/21 00:26:43 tgl Exp $ + * $Id: catversion.h,v 1.122 2002/04/21 19:48:22 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200204201 +#define CATALOG_VERSION_NO 200204211 #endif diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index 2bc01d6b171aa12cb7eeb2ad6641e29a23b3c970..27ed668f7b6b0153a5e71a38a669fce4ed9337f1 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_control.h,v 1.6 2001/11/05 17:46:32 momjian Exp $ + * $Id: pg_control.h,v 1.7 2002/04/21 19:48:23 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,7 @@ /* Version identifier for this pg_control format */ -#define PG_CONTROL_VERSION 71 +#define PG_CONTROL_VERSION 72 /* * Body of CheckPoint XLOG records. This is declared here because we keep @@ -106,7 +106,15 @@ typedef struct ControlFileData */ uint32 blcksz; /* block size for this DB */ uint32 relseg_size; /* blocks per segment of large relation */ + + uint32 nameDataLen; /* catalog name field width */ + uint32 funcMaxArgs; /* maximum number of function arguments */ + + /* flag indicating internal format of timestamp, interval, time */ + uint32 enableIntTimes; /* int64 storage enabled? */ + /* active locales --- "C" if compiled without USE_LOCALE: */ + uint32 localeBuflen; char lc_collate[LOCALE_NAME_BUFLEN]; char lc_ctype[LOCALE_NAME_BUFLEN]; } ControlFileData; diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 0cd1f5d96f0578d0d5fd0f37cb49a7d91a8e8bef..90484c95c8bb5f1fb12932f91324f8a6aeb204ea 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_operator.h,v 1.102 2002/04/16 23:08:11 tgl Exp $ + * $Id: pg_operator.h,v 1.103 2002/04/21 19:48:23 thomas Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -476,6 +476,8 @@ DATA(insert OID = 1068 ( ">" PGNSP PGUID 0 b t f 1043 1043 16 1066 1067 0 0 DATA(insert OID = 1069 ( ">=" PGNSP PGUID 0 b t f 1043 1043 16 1067 1066 0 0 0 0 varcharge scalargtsel scalargtjoinsel )); /* date operators */ +DATA(insert OID = 1076 ( "+" PGNSP PGUID 0 b t f 1082 1186 1114 0 0 0 0 0 0 date_pl_interval - - )); +DATA(insert OID = 1077 ( "-" PGNSP PGUID 0 b t f 1082 1186 1114 0 0 0 0 0 0 date_mi_interval - - )); DATA(insert OID = 1093 ( "=" PGNSP PGUID 0 b t t 1082 1082 16 1093 1094 1095 1095 1095 1097 date_eq eqsel eqjoinsel )); DATA(insert OID = 1094 ( "<>" PGNSP PGUID 0 b t f 1082 1082 16 1094 1093 0 0 0 0 date_ne neqsel neqjoinsel )); DATA(insert OID = 1095 ( "<" PGNSP PGUID 0 b t f 1082 1082 16 1097 1098 0 0 0 0 date_lt scalarltsel scalarltjoinsel )); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index f8863d9340f6818fc5702c3493d0b4bb6f6d56b3..3cdf0a488e9ce98d423b49f2db31c4a0689ea14a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.228 2002/04/18 20:01:10 tgl Exp $ + * $Id: pg_proc.h,v 1.229 2002/04/21 19:48:23 thomas Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -1280,7 +1280,7 @@ DESCR("convert timetz to text"); /* OIDS 1000 - 1999 */ -DATA(insert OID = 1026 ( timezone PGNSP PGUID 12 f t f t f s 2 25 "1186 1184" 100 0 0 100 timestamptz_izone - _null_ )); +DATA(insert OID = 1026 ( timezone PGNSP PGUID 12 f t f t f s 2 1186 "1186 1184" 100 0 0 100 timestamptz_izone - _null_ )); DESCR("time zone"); DATA(insert OID = 1029 ( nullvalue PGNSP PGUID 12 f t f f f i 1 16 "0" 100 0 0 100 nullvalue - _null_ )); @@ -1414,8 +1414,8 @@ DATA(insert OID = 1156 ( timestamptz_ge PGNSP PGUID 12 f t f t f i 2 16 "1184 DESCR("greater-than-or-equal"); DATA(insert OID = 1157 ( timestamptz_gt PGNSP PGUID 12 f t f t f i 2 16 "1184 1184" 100 0 0 100 timestamp_gt - _null_ )); DESCR("greater-than"); -DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f t f t f s 2 25 "25 1184" 100 0 0 100 timestamptz_zone - _null_ )); -DESCR("time zone"); +DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f t f t f s 2 1114 "25 1184" 100 0 0 100 timestamptz_zone - _null_ )); +DESCR("timestamp at a specified time zone"); DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f t f t f s 1 1186 "0" 100 0 0 100 interval_in - _null_ )); DESCR("(internal)"); @@ -1710,13 +1710,13 @@ DATA(insert OID = 1383 ( date_part PGNSP PGUID 14 f t f t f s 2 701 "25 703 DESCR("extract field from reltime"); DATA(insert OID = 1384 ( date_part PGNSP PGUID 14 f t f t f i 2 701 "25 1082" 100 0 0 100 "select date_part($1, cast($2 as timestamp without time zone))" - _null_ )); DESCR("extract field from date"); -DATA(insert OID = 1385 ( date_part PGNSP PGUID 14 f t f t f i 2 701 "25 1083" 100 0 0 100 "select date_part($1, cast($2 as time with time zone))" - _null_ )); +DATA(insert OID = 1385 ( date_part PGNSP PGUID 12 f t f t f i 2 701 "25 1083" 100 0 0 100 time_part - _null_ )); DESCR("extract field from time"); DATA(insert OID = 1386 ( age PGNSP PGUID 14 f t f t f s 1 1186 "1184" 100 0 0 100 "select age(cast(current_date as timestamp with time zone), $1)" - _null_ )); DESCR("date difference from today preserving months and years"); -DATA(insert OID = 1388 ( timetz PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100 timestamptz_timetz - _null_ )); -DESCR("convert timestamp to timetz"); +DATA(insert OID = 1388 ( timetz PGNSP PGUID 12 f t f t f s 1 1266 "1184" 100 0 0 100 timestamptz_timetz - _null_ )); +DESCR("convert timestamptz to timetz"); DATA(insert OID = 1389 ( isfinite PGNSP PGUID 12 f t f t f i 1 16 "1184" 100 0 0 100 timestamp_finite - _null_ )); DESCR("boolean test"); @@ -2769,6 +2769,8 @@ DESCR("return position of substring"); DATA(insert OID = 2015 ( btrim PGNSP PGUID 12 f t f t f i 2 17 "17 17" 100 0 0 100 byteatrim - _null_ )); DESCR("trim both ends of string"); +DATA(insert OID = 2019 ( time PGNSP PGUID 12 f t f t f s 1 1083 "1184" 100 0 0 100 timestamptz_time - _null_ )); +DESCR("convert timestamptz to time"); DATA(insert OID = 2020 ( date_trunc PGNSP PGUID 12 f t f t f i 2 1114 "25 1114" 100 0 0 100 timestamp_trunc - _null_ )); DESCR("truncate timestamp to specified units"); DATA(insert OID = 2021 ( date_part PGNSP PGUID 12 f t f t f i 2 701 "25 1114" 100 0 0 100 timestamp_part - _null_ )); @@ -2801,9 +2803,9 @@ DATA(insert OID = 2035 ( timestamp_smaller PGNSP PGUID 12 f t f t f i 2 1114 "1 DESCR("smaller of two"); DATA(insert OID = 2036 ( timestamp_larger PGNSP PGUID 12 f t f t f i 2 1114 "1114 1114" 100 0 0 100 timestamp_larger - _null_ )); DESCR("larger of two"); -DATA(insert OID = 2037 ( timetz PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100 timetz_zone - _null_ )); +DATA(insert OID = 2037 ( timezone PGNSP PGUID 12 f t f t f s 2 1266 "25 1266" 100 0 0 100 timetz_zone - _null_ )); DESCR("time with time zone"); -DATA(insert OID = 2038 ( timetz PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100 timetz_izone - _null_ )); +DATA(insert OID = 2038 ( timezone PGNSP PGUID 12 f t f t f i 2 1266 "1186 1266" 100 0 0 100 timetz_izone - _null_ )); DESCR("time with time zone"); DATA(insert OID = 2041 ( overlaps PGNSP PGUID 12 f t f f f i 4 16 "1114 1114 1114 1114" 100 0 0 100 overlaps_timestamp - _null_ )); DESCR("SQL92 interval comparison"); @@ -2843,10 +2845,15 @@ DATA(insert OID = 2058 ( age PGNSP PGUID 12 f t f t f i 2 1186 "1114 1114" 1 DESCR("date difference preserving months and years"); DATA(insert OID = 2059 ( age PGNSP PGUID 14 f t f t f s 1 1186 "1114" 100 0 0 100 "select age(cast(current_date as timestamp without time zone), $1)" - _null_ )); DESCR("date difference from today preserving months and years"); + DATA(insert OID = 2069 ( timezone PGNSP PGUID 12 f t f t f s 2 1184 "25 1114" 100 0 0 100 timestamp_zone - _null_ )); -DESCR("time zone"); +DESCR("timestamp at a specified time zone"); DATA(insert OID = 2070 ( timezone PGNSP PGUID 12 f t f t f s 2 1184 "1186 1114" 100 0 0 100 timestamp_izone - _null_ )); DESCR("time zone"); +DATA(insert OID = 2071 ( date_pl_interval PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) + $2;" - _null_ )); +DESCR("add"); +DATA(insert OID = 2072 ( date_mi_interval PGNSP PGUID 14 f t f t f i 2 1114 "1082 1186" 100 0 0 100 "select cast($1 as timestamp without time zone) - $2;" - _null_ )); +DESCR("subtract"); /* Aggregates (moved here from pg_aggregate for 7.3) */ diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 2cae99aaefb64d74241ab94e3ff3d305823db457..80b904181d316dbc41243e5ee1ed9324c4b4a83b 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -8,7 +8,7 @@ * or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your * changes will be overwritten the next time you run configure. * - * $Id: pg_config.h.in,v 1.22 2002/04/21 00:22:52 ishii Exp $ + * $Id: pg_config.h.in,v 1.23 2002/04/21 19:48:19 thomas Exp $ */ #ifndef PG_CONFIG_H @@ -33,6 +33,9 @@ /* A canonical string containing the version number, platform, and C compiler */ #undef PG_VERSION_STR +/* Set to 1 if you want 64-bit integer timestamp and interval support (--enable-integer-datetimes) */ +#undef USE_INTEGER_DATETIMES + /* Set to 1 if you want cyrillic recode (--enable-recode) */ #undef CYR_RECODE diff --git a/src/include/utils/date.h b/src/include/utils/date.h index ca911c0f7f0d650cb908a4476aff021e670852b4..209dd74d9dcb8b1731e2ee7b88896d43e8a9ccad 100644 --- a/src/include/utils/date.h +++ b/src/include/utils/date.h @@ -7,27 +7,41 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: date.h,v 1.17 2001/11/05 17:46:36 momjian Exp $ + * $Id: date.h,v 1.18 2002/04/21 19:48:31 thomas Exp $ * *------------------------------------------------------------------------- */ #ifndef DATE_H #define DATE_H +#include "c.h" #include "fmgr.h" typedef int32 DateADT; +#ifdef HAVE_INT64_TIMESTAMP +typedef int64 TimeADT; +#else typedef float8 TimeADT; +#endif typedef struct { - double time; /* all time units other than months and - * years */ - int32 zone; /* numeric time zone, in seconds */ +#ifdef HAVE_INT64_TIMESTAMP + int64 time; /* all time units other than months and years */ +#else + double time; /* all time units other than months and years */ +#endif + int32 zone; /* numeric time zone, in seconds */ } TimeTzADT; +#ifdef HAVE_INT64_TIMESTAMP +#define MAX_TIME_PRECISION 6 +#else +#define MAX_TIME_PRECISION 13 +#endif + /* * Macros for fmgr-callable functions. * @@ -90,6 +104,7 @@ extern Datum time_larger(PG_FUNCTION_ARGS); extern Datum time_smaller(PG_FUNCTION_ARGS); extern Datum time_mi_time(PG_FUNCTION_ARGS); extern Datum timestamp_time(PG_FUNCTION_ARGS); +extern Datum timestamptz_time(PG_FUNCTION_ARGS); extern Datum time_interval(PG_FUNCTION_ARGS); extern Datum interval_time(PG_FUNCTION_ARGS); extern Datum text_time(PG_FUNCTION_ARGS); @@ -97,6 +112,7 @@ extern Datum time_text(PG_FUNCTION_ARGS); extern Datum time_pl_interval(PG_FUNCTION_ARGS); extern Datum time_mi_interval(PG_FUNCTION_ARGS); extern Datum interval_pl_time(PG_FUNCTION_ARGS); +extern Datum time_part(PG_FUNCTION_ARGS); extern Datum timetz_in(PG_FUNCTION_ARGS); extern Datum timetz_out(PG_FUNCTION_ARGS); diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 7858498a953fe267d501b4bab028942a8016713c..a889bd6c7bcc728cf92ce41ac980600daf4abbe1 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: datetime.h,v 1.28 2002/01/01 02:54:33 thomas Exp $ + * $Id: datetime.h,v 1.29 2002/04/21 19:48:31 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -198,15 +198,26 @@ typedef struct /* TMODULO() * Macro to replace modf(), which is broken on some platforms. + * t = input and remainder + * q = integer part + * u = divisor */ +#ifdef HAVE_INT64_TIMESTAMP +#define TMODULO(t,q,u) \ +do { \ + q = (t / u); \ + if (q != 0) t -= (q * u); \ +} while(0) +#else #define TMODULO(t,q,u) \ do { \ q = ((t < 0)? ceil(t / u): floor(t / u)); \ - if (q != 0) \ - t -= rint(q * u); \ + if (q != 0) t -= rint(q * u); \ } while(0) +#endif -#ifdef __CYGWIN__ +/* Global variable holding time zone information. */ +#if defined(__CYGWIN__) || defined(N_PLAT_NLM) #define TIMEZONE_GLOBAL _timezone #else #define TIMEZONE_GLOBAL timezone @@ -250,7 +261,7 @@ extern int day_tab[2][13]; extern void GetCurrentTime(struct tm * tm); -extern void GetCurrentTimeUsec(struct tm * tm, double *fsec); +extern void GetCurrentTimeUsec(struct tm * tm, fsec_t *fsec); extern void j2date(int jd, int *year, int *month, int *day); extern int date2j(int year, int month, int day); @@ -259,22 +270,22 @@ extern int ParseDateTime(char *timestr, char *lowstr, int maxfields, int *numfields); extern int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, - struct tm * tm, double *fsec, int *tzp); + struct tm * tm, fsec_t *fsec, int *tzp); extern int DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, - struct tm * tm, double *fsec, int *tzp); + struct tm * tm, fsec_t *fsec, int *tzp); -extern int DecodeDateDelta(char **field, int *ftype, +extern int DecodeInterval(char **field, int *ftype, int nf, int *dtype, - struct tm * tm, double *fsec); + struct tm * tm, fsec_t *fsec); extern int DetermineLocalTimeZone(struct tm * tm); extern int EncodeDateOnly(struct tm * tm, int style, char *str); -extern int EncodeTimeOnly(struct tm * tm, double fsec, int *tzp, int style, char *str); -extern int EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str); -extern int EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str); +extern int EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str); +extern int EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str); +extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str); extern int DecodeSpecial(int field, char *lowtoken, int *val); extern int DecodeUnits(int field, char *lowtoken, int *val); diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h index e2db00da38eb81e8f42692e008bd3baba96a83a9..e2947e0050863f95714d94c9704bff1914fa2017 100644 --- a/src/include/utils/int8.h +++ b/src/include/utils/int8.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: int8.h,v 1.31 2001/11/05 17:46:36 momjian Exp $ + * $Id: int8.h,v 1.32 2002/04/21 19:48:31 thomas Exp $ * * NOTES * These data types are supported on all 64-bit architectures, and may @@ -15,17 +15,25 @@ * is not currently supported, then please try to make it so, then post * patches to the postgresql.org hackers mailing list. * - * This code was written for and originally appeared in the contrib - * directory as a user-defined type. - * - thomas 1998-06-08 - * *------------------------------------------------------------------------- */ #ifndef INT8_H #define INT8_H +#include "c.h" #include "fmgr.h" +/* this should be set in pg_config.h, but just in case it wasn't: */ +#ifndef INT64_FORMAT +#warning "Broken pg_config.h should have defined INT64_FORMAT" +#define INT64_FORMAT "%ld" +#endif + +#ifdef HAVE_LL_CONSTANTS +#define INT64CONST(x) ((int64) x##LL) +#else +#define INT64CONST(x) ((int64) x) +#endif extern Datum int8in(PG_FUNCTION_ARGS); extern Datum int8out(PG_FUNCTION_ARGS); diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 3ea20f3ea2440357d851b62bc3a65507dd062027..a4da9dd5d6b9dbd27e7e0c784bf29316db2d7c42 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: timestamp.h,v 1.24 2001/11/05 17:46:36 momjian Exp $ + * $Id: timestamp.h,v 1.25 2002/04/21 19:48:31 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -18,8 +18,11 @@ #include <limits.h> #include <float.h> +#include "c.h" #include "fmgr.h" - +#ifdef HAVE_INT64_TIMESTAMP +#include "utils/int8.h" +#endif /* * Timestamp represents absolute time. @@ -31,16 +34,22 @@ * consisting of a beginning and ending time, not a time span - thomas 97/03/20 */ +#ifdef HAVE_INT64_TIMESTAMP +typedef int64 Timestamp; +typedef int64 TimestampTz; +#else typedef double Timestamp; - typedef double TimestampTz; +#endif typedef struct { - double time; /* all time units other than months and - * years */ - int32 month; /* months and years, after time for - * alignment */ +#ifdef HAVE_INT64_TIMESTAMP + int64 time; /* all time units other than months and years */ +#else + double time; /* all time units other than months and years */ +#endif + int32 month; /* months and years, after time for alignment */ } Interval; @@ -50,6 +59,27 @@ typedef struct * For Timestamp, we make use of the same support routines as for float8. * Therefore Timestamp is pass-by-reference if and only if float8 is! */ +#ifdef HAVE_INT64_TIMESTAMP +#define DatumGetTimestamp(X) ((Timestamp) DatumGetInt64(X)) +#define DatumGetTimestampTz(X) ((TimestampTz) DatumGetInt64(X)) +#define DatumGetIntervalP(X) ((Interval *) DatumGetPointer(X)) + +#define TimestampGetDatum(X) Int64GetDatum(X) +#define TimestampTzGetDatum(X) Int64GetDatum(X) +#define IntervalPGetDatum(X) PointerGetDatum(X) + +#define PG_GETARG_TIMESTAMP(n) PG_GETARG_INT64(n) +#define PG_GETARG_TIMESTAMPTZ(n) PG_GETARG_INT64(n) +#define PG_GETARG_INTERVAL_P(n) DatumGetIntervalP(PG_GETARG_DATUM(n)) + +#define PG_RETURN_TIMESTAMP(x) PG_RETURN_INT64(x) +#define PG_RETURN_TIMESTAMPTZ(x) PG_RETURN_INT64(x) +#define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x) + +#define DT_NOBEGIN (-INT64CONST(0x7fffffffffffffff) - 1) +#define DT_NOEND (INT64CONST(0x7fffffffffffffff)) + +#else #define DatumGetTimestamp(X) ((Timestamp) DatumGetFloat8(X)) #define DatumGetTimestampTz(X) ((TimestampTz) DatumGetFloat8(X)) #define DatumGetIntervalP(X) ((Interval *) DatumGetPointer(X)) @@ -66,7 +96,6 @@ typedef struct #define PG_RETURN_TIMESTAMPTZ(x) return TimestampTzGetDatum(x) #define PG_RETURN_INTERVAL_P(x) return IntervalPGetDatum(x) - #ifdef HUGE_VAL #define DT_NOBEGIN (-HUGE_VAL) #define DT_NOEND (HUGE_VAL) @@ -74,6 +103,7 @@ typedef struct #define DT_NOBEGIN (-DBL_MAX) #define DT_NOEND (DBL_MAX) #endif +#endif #define TIMESTAMP_NOBEGIN(j) do {j = DT_NOBEGIN;} while (0) #define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN) @@ -83,8 +113,21 @@ typedef struct #define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j)) + +#define MAX_TIMESTAMP_PRECISION 6 +#define MAX_INTERVAL_PRECISION 6 + +#ifdef HAVE_INT64_TIMESTAMP +typedef int32 fsec_t; + +#define SECONDS_TO_TIMESTAMP(x) (INT64CONST(x000000)) +#else +typedef double fsec_t; + +#define SECONDS_TO_TIMESTAMP(x) (xe0) #define TIME_PREC_INV 1000000.0 #define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV) +#endif /* @@ -167,13 +210,13 @@ extern Datum now(PG_FUNCTION_ARGS); /* Internal routines (not fmgr-callable) */ -extern int tm2timestamp(struct tm * tm, double fsec, int *tzp, Timestamp *dt); +extern int tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *dt); extern int timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, - double *fsec, char **tzn); -extern void dt2time(Timestamp dt, int *hour, int *min, double *sec); + fsec_t *fsec, char **tzn); +extern void dt2time(Timestamp dt, int *hour, int *min, int *sec, fsec_t *fsec); -extern int interval2tm(Interval span, struct tm * tm, float8 *fsec); -extern int tm2interval(struct tm * tm, double fsec, Interval *span); +extern int interval2tm(Interval span, struct tm * tm, fsec_t *fsec); +extern int tm2interval(struct tm * tm, fsec_t fsec, Interval *span); extern Timestamp SetEpochTimestamp(void); extern void GetEpochTime(struct tm * tm); diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index bcace859ce7424d4a3b6414a3f983da4ee5cbb32..4315019210d04f3fac8d3a3a75b8d2bf2296beaa 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -264,22 +264,22 @@ SELECT date '2001-02-03' + time with time zone '04:05:06 UTC' AS "Date + Time UT (1 row) SELECT date '1991-02-03' + interval '2 years' AS "Add Two Years"; - Add Two Years ------------------------------- - Wed Feb 03 00:00:00 1993 PST + Add Two Years +-------------------------- + Wed Feb 03 00:00:00 1993 (1 row) SELECT date '2001-12-13' - interval '2 years' AS "Subtract Two Years"; - Subtract Two Years ------------------------------- - Mon Dec 13 00:00:00 1999 PST + Subtract Two Years +-------------------------- + Mon Dec 13 00:00:00 1999 (1 row) -- subtract time from date should not make sense; use interval instead SELECT date '1991-02-03' - time '04:05:06' AS "Subtract Time"; - Subtract Time ------------------------------- - Sat Feb 02 19:54:54 1991 PST + Subtract Time +-------------------------- + Sat Feb 02 19:54:54 1991 (1 row) SELECT date '1991-02-03' - time with time zone '04:05:06 UTC' AS "Subtract Time UTC"; @@ -406,7 +406,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL; | Sat Feb 14 17:32:01 1998 | Sun Feb 15 17:32:01 1998 | Mon Feb 16 17:32:01 1998 - | Thu Feb 16 17:32 0096 BC + | Thu Feb 16 17:32:01 0096 BC | Sun Feb 16 17:32:01 0098 | Fri Feb 16 17:32:01 0598 | Wed Feb 16 17:32:01 1098 @@ -475,7 +475,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL; | Wed Feb 14 17:32:01 1996 | Thu Feb 15 17:32:01 1996 | Fri Feb 16 17:32:01 1996 - | Mon Feb 16 17:32 0098 BC + | Mon Feb 16 17:32:01 0098 BC | Thu Feb 16 17:32:01 0096 | Tue Feb 16 17:32:01 0596 | Sun Feb 16 17:32:01 1096 @@ -622,7 +622,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Sat Feb 14 17:32:01 1998 PST | Sun Feb 15 17:32:01 1998 PST | Mon Feb 16 17:32:01 1998 PST - | Thu Feb 16 17:32 0096 BC + | Thu Feb 16 17:32:01 0096 BC | Sun Feb 16 17:32:01 0098 | Fri Feb 16 17:32:01 0598 | Wed Feb 16 17:32:01 1098 @@ -691,7 +691,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Wed Feb 14 17:32:01 1996 PST | Thu Feb 15 17:32:01 1996 PST | Fri Feb 16 17:32:01 1996 PST - | Mon Feb 16 17:32 0098 BC + | Mon Feb 16 17:32:01 0098 BC | Thu Feb 16 17:32:01 0096 | Tue Feb 16 17:32:01 0596 | Sun Feb 16 17:32:01 1096 @@ -1519,7 +1519,7 @@ SELECT (time '00:00', interval '1 hour') f (1 row) -CREATE TABLE TEMP_TIMESTAMP (f1 timestamp); +CREATE TABLE TEMP_TIMESTAMP (f1 timestamp with time zone); -- get some candidate input values INSERT INTO TEMP_TIMESTAMP (f1) SELECT d1 FROM TIMESTAMP_TBL @@ -1883,8 +1883,9 @@ SELECT '' AS "160", d.f1 AS "timestamp", t.f1 AS "interval", d.f1 - t.f1 AS minu | Sat Sep 22 18:19:20 2001 PDT | @ 14 secs ago | Sat Sep 22 18:19:34 2001 PDT (160 rows) -SELECT '' AS "16", d.f1 AS "timestamp", timestamp '1980-01-06 00:00 GMT' AS gpstime_zero, - d.f1 - timestamp '1980-01-06 00:00 GMT' AS difference +SELECT '' AS "16", d.f1 AS "timestamp", + timestamp with time zone '1980-01-06 00:00 GMT' AS gpstime_zero, + d.f1 - timestamp with time zone '1980-01-06 00:00 GMT' AS difference FROM TEMP_TIMESTAMP d ORDER BY difference; 16 | timestamp | gpstime_zero | difference @@ -2305,7 +2306,7 @@ SELECT '' AS two, d1 AS "timestamp", abstime(d1) AS abstime SELECT '' AS three, f1 as abstime, cast(f1 as timestamp) AS "timestamp" FROM ABSTIME_TBL WHERE NOT isfinite(f1); -ERROR: Unable to convert abstime 'invalid' to timestamptz +ERROR: Unable to convert abstime 'invalid' to timestamp SELECT '' AS ten, f1 AS interval, reltime(f1) AS reltime FROM INTERVAL_TBL; ten | interval | reltime @@ -2385,7 +2386,7 @@ SELECT '' AS "64", d1 AS us_postgres FROM TIMESTAMP_TBL; | Fri Feb 14 17:32:01 1997 | Sat Feb 15 17:32:01 1997 | Sun Feb 16 17:32:01 1997 - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -2467,7 +2468,7 @@ SELECT '' AS "64", d1 AS us_iso FROM TIMESTAMP_TBL; | 1997-02-14 17:32:01 | 1997-02-15 17:32:01 | 1997-02-16 17:32:01 - | 0097-02-16 17:32 BC + | 0097-02-16 17:32:01 BC | 0097-02-16 17:32:01 | 0597-02-16 17:32:01 | 1097-02-16 17:32:01 @@ -2551,7 +2552,7 @@ SELECT '' AS "64", d1 AS us_sql FROM TIMESTAMP_TBL; | 02/14/1997 17:32:01 | 02/15/1997 17:32:01 | 02/16/1997 17:32:01 - | 02/16/0097 17:32 BC + | 02/16/0097 17:32:01 BC | 02/16/0097 17:32:01 | 02/16/0597 17:32:01 | 02/16/1097 17:32:01 @@ -2642,7 +2643,7 @@ SELECT '' AS "65", d1 AS european_postgres FROM TIMESTAMP_TBL; | Fri 14 Feb 17:32:01 1997 | Sat 15 Feb 17:32:01 1997 | Sun 16 Feb 17:32:01 1997 - | Tue 16 Feb 17:32 0097 BC + | Tue 16 Feb 17:32:01 0097 BC | Sat 16 Feb 17:32:01 0097 | Thu 16 Feb 17:32:01 0597 | Tue 16 Feb 17:32:01 1097 @@ -2727,7 +2728,7 @@ SELECT '' AS "65", d1 AS european_iso FROM TIMESTAMP_TBL; | 1997-02-14 17:32:01 | 1997-02-15 17:32:01 | 1997-02-16 17:32:01 - | 0097-02-16 17:32 BC + | 0097-02-16 17:32:01 BC | 0097-02-16 17:32:01 | 0597-02-16 17:32:01 | 1097-02-16 17:32:01 @@ -2812,7 +2813,7 @@ SELECT '' AS "65", d1 AS european_sql FROM TIMESTAMP_TBL; | 14/02/1997 17:32:01 | 15/02/1997 17:32:01 | 16/02/1997 17:32:01 - | 16/02/0097 17:32 BC + | 16/02/0097 17:32:01 BC | 16/02/0097 17:32:01 | 16/02/0597 17:32:01 | 16/02/1097 17:32:01 diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out index ad2f1d7ec9766ab49d5d33d16371925fedc394f2..e7c8cc8086b7c42a0e63058eabcf367e1ed80ba2 100644 --- a/src/test/regress/expected/timestamp.out +++ b/src/test/regress/expected/timestamp.out @@ -183,7 +183,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMP_TBL; | Fri Feb 14 17:32:01 1997 | Sat Feb 15 17:32:01 1997 | Sun Feb 16 17:32:01 1997 - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -265,11 +265,11 @@ SELECT '' AS "48", d1 FROM TIMESTAMP_TBL SELECT '' AS "15", d1 FROM TIMESTAMP_TBL WHERE d1 < timestamp without time zone '1997-01-02'; - 15 | d1 -----+-------------------------- + 15 | d1 +----+----------------------------- | -infinity | Thu Jan 01 00:00:00 1970 - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -335,7 +335,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMP_TBL | Fri Feb 14 17:32:01 1997 | Sat Feb 15 17:32:01 1997 | Sun Feb 16 17:32:01 1997 - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -362,12 +362,12 @@ SELECT '' AS "63", d1 FROM TIMESTAMP_TBL SELECT '' AS "16", d1 FROM TIMESTAMP_TBL WHERE d1 <= timestamp without time zone '1997-01-02'; - 16 | d1 -----+-------------------------- + 16 | d1 +----+----------------------------- | -infinity | Thu Jan 01 00:00:00 1970 | Thu Jan 02 00:00:00 1997 - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index 1741add0ac0d45a304b12c246b5f3cdf0ce0f61d..403a0bbd4afc94cf72ab52a32e343d6a72b3f704 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -178,7 +178,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL; | Fri Feb 14 17:32:01 1997 PST | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -264,7 +264,7 @@ SELECT '' AS "15", d1 FROM TIMESTAMPTZ_TBL ----+------------------------------ | -infinity | Wed Dec 31 16:00:00 1969 PST - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -330,7 +330,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL | Fri Feb 14 17:32:01 1997 PST | Sat Feb 15 17:32:01 1997 PST | Sun Feb 16 17:32:01 1997 PST - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 @@ -362,7 +362,7 @@ SELECT '' AS "16", d1 FROM TIMESTAMPTZ_TBL | -infinity | Wed Dec 31 16:00:00 1969 PST | Thu Jan 02 00:00:00 1997 PST - | Tue Feb 16 17:32 0097 BC + | Tue Feb 16 17:32:01 0097 BC | Sat Feb 16 17:32:01 0097 | Thu Feb 16 17:32:01 0597 | Tue Feb 16 17:32:01 1097 diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql index 019c3e9ffd7f77d57008d64e895a656f817d50e2..136e6c6c6517c046afe3b27bec4d9660b4084593 100644 --- a/src/test/regress/sql/horology.sql +++ b/src/test/regress/sql/horology.sql @@ -214,7 +214,7 @@ SELECT (time '00:00', interval '1 hour') SELECT (time '00:00', interval '1 hour') OVERLAPS (time '01:30', interval '1 day') AS "False"; -CREATE TABLE TEMP_TIMESTAMP (f1 timestamp); +CREATE TABLE TEMP_TIMESTAMP (f1 timestamp with time zone); -- get some candidate input values @@ -236,8 +236,9 @@ SELECT '' AS "160", d.f1 AS "timestamp", t.f1 AS "interval", d.f1 - t.f1 AS minu WHERE isfinite(d.f1) ORDER BY minus, "timestamp", "interval"; -SELECT '' AS "16", d.f1 AS "timestamp", timestamp '1980-01-06 00:00 GMT' AS gpstime_zero, - d.f1 - timestamp '1980-01-06 00:00 GMT' AS difference +SELECT '' AS "16", d.f1 AS "timestamp", + timestamp with time zone '1980-01-06 00:00 GMT' AS gpstime_zero, + d.f1 - timestamp with time zone '1980-01-06 00:00 GMT' AS difference FROM TEMP_TIMESTAMP d ORDER BY difference;