diff options
author | Thomas G. Lockhart <lockhart@fourpalms.org> | 2001-10-20 01:02:22 +0000 |
---|---|---|
committer | Thomas G. Lockhart <lockhart@fourpalms.org> | 2001-10-20 01:02:22 +0000 |
commit | 424d9389d61997266aa17dec7ac8247a2459fdef (patch) | |
tree | 39e997c31de025e9aaa051c75b2fa5e1d1257bd9 /src/backend/utils/adt | |
parent | 3a484d9e99f8ac6e757a09b65e376a8f6f3a0920 (diff) | |
download | postgresql-424d9389d61997266aa17dec7ac8247a2459fdef.tar.gz postgresql-424d9389d61997266aa17dec7ac8247a2459fdef.zip |
Fix transposed arguments for typmod for one INTERVAL production.
Mask both typmod subfields for INTERVAL to avoid setting the high bit,
per dire warning from Tom Lane.
Clear tmask for DTK_ISO_TIME case to avoid time zone troubles.
Symptom reported by Tom Lane.
Clean up checking for valid time zone info in output routine.
This should now work for both SQL99 and Unix-style time zones.
Put in explicit check for INTERVAL() typmod rounding to avoid accumulating
cruft in the lower bits. Not sure that this helps, but we'll need to do
something. The symptom is visible with a query like
select interval(2) '10000 days 01:02:03.040506';
Regression tests are patched to repair the Tom Lane symptom, and all pass.
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/datetime.c | 73 | ||||
-rw-r--r-- | src/backend/utils/adt/nabstime.c | 20 | ||||
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 26 |
3 files changed, 83 insertions, 36 deletions
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 275231983ee..6d6fbd6b456 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.73 2001/10/18 17:30:15 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.74 2001/10/20 01:02:18 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -385,17 +385,22 @@ j2day(int date) } /* j2day() */ +/* TrimTrailingZeros() + * ... resulting from printing numbers with full precision. + */ void TrimTrailingZeros(char *str) { int len = strlen(str); +#if 0 /* chop off trailing one to cope with interval rounding */ if (strcmp((str + len - 4), "0001") == 0) { len -= 4; *(str + len) = '\0'; } +#endif /* chop off trailing zeros... */ while ((*(str + len - 1) == '0') @@ -905,11 +910,12 @@ DecodeDateTime(char **field, int *ftype, int nf, break; case UNITS: - ptype = val; tmask = 0; + ptype = val; break; case DTK_ISO_TIME: + tmask = 0; if ((i < 1) || (i >= (nf-1)) || (ftype[i-1] != DTK_DATE) || (ftype[i+1] != DTK_TIME)) @@ -2267,10 +2273,10 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha } /* tzp == NULL indicates that we don't want *any* time zone info in the output string. - * *tzn != NULL indicates that we *have* time zone info available. + * *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) && (*tzn != NULL) && (tm->tm_isdst >= 0)) + if ((tzp != NULL) && (tm->tm_isdst >= 0)) { hour = -(*tzp / 3600); min = ((abs(*tzp) / 60) % 60); @@ -2315,14 +2321,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha sprintf((str + strlen(str)), ":%02.0f", sec); } - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn); - - else if (tzp != NULL) + 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 (*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); + } } } else @@ -2353,14 +2363,18 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha sprintf((str + strlen(str)), ":%02.0f", sec); } - if ((*tzn != NULL) && (tm->tm_isdst >= 0)) - sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn); - - else if (tzp != NULL) + 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 (*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); + } } } else @@ -2403,14 +2417,23 @@ EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, cha sprintf((str + strlen(str)), " %04d", tm->tm_year); - if ((tzp != NULL) && (*tzn != NULL) && (tm->tm_isdst >= 0)) - sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn); - - else if (HasCTZSet && (tzp != NULL)) + 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 (*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); + } } } else diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index 55642a1c096..29608aa78db 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.89 2001/10/18 19:52:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.90 2001/10/20 01:02:18 thomas Exp $ * * NOTES * @@ -256,7 +256,7 @@ GetCurrentAbsoluteTimeUsec(int *usec) }; return (AbsoluteTime) now; -} /* GetCurrentAbsoluteTime() */ +} /* GetCurrentAbsoluteTimeUsec() */ void @@ -344,7 +344,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) { *tzp = CTimeZone; tm->tm_gmtoff = CTimeZone; - tm->tm_isdst = -1; + tm->tm_isdst = 0; tm->tm_zone = NULL; if (tzn != NULL) *tzn = NULL; @@ -366,6 +366,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) } } } + else + { + tm->tm_isdst = -1; + } #elif defined(HAVE_INT_TIMEZONE) if (tzp != NULL) { @@ -376,7 +380,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) if (HasCTZSet) { *tzp = CTimeZone; - tm->tm_isdst = -1; + tm->tm_isdst = 0; if (tzn != NULL) *tzn = NULL; } @@ -397,6 +401,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) } } } + else + { + tm->tm_isdst = -1; + } #endif #else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */ if (tzp != NULL) @@ -426,6 +434,10 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) } } } + else + { + tm->tm_isdst = -1; + } #endif return; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index efe4a501463..f39e85b235e 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.57 2001/10/18 19:54:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/timestamp.c,v 1.58 2001/10/20 01:02:18 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -374,14 +374,14 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) { if (typmod != -1) { - int range = ((typmod >> 16) & 0xFFFF); + int range = ((typmod >> 16) & 0x7FFF); int precision = (typmod & 0xFFFF); - if (range == 0xFFFF) + if (range == 0x7FFF) { /* Do nothing... */ } - if (range == MASK(YEAR)) + else if (range == MASK(YEAR)) { interval->month = ((interval->month / 12) * 12); interval->time = 0; @@ -483,7 +483,18 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) IntervalScale = pow(10.0, IntervalTypmod); } - interval->time = (rint(interval->time * IntervalScale) / IntervalScale); + /* 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); } } @@ -671,14 +682,15 @@ timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, double *fsec, char **tzn) else { *tzp = 0; - tm->tm_isdst = 0; + /* Mark this as *no* time zone available */ + tm->tm_isdst = -1; if (tzn != NULL) *tzn = NULL; } } else { - tm->tm_isdst = 0; + tm->tm_isdst = -1; if (tzn != NULL) *tzn = NULL; } |