diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 59db3b180c..4f5f5d6b7e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.264 2001/10/18 23:16:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.265 2001/10/20 01:02:14 thomas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -887,13 +887,18 @@ zone_value: Sconst | ConstInterval Sconst opt_interval { A_Const *n = (A_Const *) makeStringConst($2, $1); - n->typename->typmod = (($3 << 16) | 0xFFFF); + if ($3 != -1) + n->typename->typmod = (($3 << 16) | 0xFFFF); $$ = (Node *)n; } | ConstInterval '(' Iconst ')' Sconst opt_interval { A_Const *n = (A_Const *) makeStringConst($5, $1); - n->typename->typmod = (($3 << 16) | $6); + if ($6 != -1) + n->typename->typmod = (($6 << 16) | $3); + else + n->typename->typmod = ((0x7FFF << 16) | $3); + $$ = (Node *)n; } | FCONST @@ -4044,12 +4049,13 @@ SimpleTypename: ConstTypename | ConstInterval opt_interval { $$ = $1; - $$->typmod = (($2 << 16) | 0xFFFF); + if ($2 != -1) + $$->typmod = ((($2 & 0x7FFF) << 16) | 0xFFFF); } | ConstInterval '(' Iconst ')' opt_interval { $$ = $1; - $$->typmod = (($5 << 16) | $3); + $$->typmod = ((($5 & 0x7FFF) << 16) | $3); } ; @@ -5625,7 +5631,9 @@ AexprConst: Iconst n->typename = $1; n->val.type = T_String; n->val.val.str = $2; - n->typename->typmod = (($3 << 16) | 0xFFFF); + /* precision is not specified, but fields may be... */ + if ($3 != -1) + n->typename->typmod = ((($3 & 0x7FFF) << 16) | 0xFFFF); $$ = (Node *)n; } | ConstInterval '(' Iconst ')' Sconst opt_interval @@ -5634,7 +5642,9 @@ AexprConst: Iconst n->typename = $1; n->val.type = T_String; n->val.val.str = $5; - n->typename->typmod = (($6 << 16) | $3); + /* precision specified, and fields may be... */ + n->typename->typmod = ((($6 & 0x7FFF) << 16) | $3); + $$ = (Node *)n; } | ParamNo diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 275231983e..6d6fbd6b45 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 55642a1c09..29608aa78d 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 efe4a50146..f39e85b235 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; } diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index c0dec19390..f911fc368f 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -359,7 +359,7 @@ SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Tue Feb 10 17:32:01 1998 PST | Tue Feb 10 17:32:01 1998 PST | Wed Jun 10 17:32:01 1998 PDT - | Sun Sep 22 11:19:20 2002 PDT + | Sun Sep 22 18:19:20 2002 PDT | Thu Mar 15 08:14:01 2001 PST | Thu Mar 15 04:14:02 2001 PST | Thu Mar 15 02:14:03 2001 PST @@ -428,7 +428,7 @@ SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMPTZ_TBL; | Sat Feb 10 17:32:01 1996 PST | Sat Feb 10 17:32:01 1996 PST | Mon Jun 10 17:32:01 1996 PDT - | Fri Sep 22 11:19:20 2000 PDT + | Fri Sep 22 18:19:20 2000 PDT | Mon Mar 15 08:14:01 1999 PST | Mon Mar 15 04:14:02 1999 PST | Mon Mar 15 02:14:03 1999 PST diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out index dd7ef75ce8..70325aac85 100644 --- a/src/test/regress/expected/timestamptz.out +++ b/src/test/regress/expected/timestamptz.out @@ -152,7 +152,7 @@ SELECT '' AS "64", d1 FROM TIMESTAMPTZ_TBL; | Mon Feb 10 17:32:01 1997 PST | Mon Feb 10 17:32:01 1997 PST | Tue Jun 10 17:32:01 1997 PDT - | Sat Sep 22 11:19:20 2001 PDT + | Sat Sep 22 18:19:20 2001 PDT | Wed Mar 15 08:14:01 2000 PST | Wed Mar 15 04:14:02 2000 PST | Wed Mar 15 02:14:03 2000 PST @@ -220,7 +220,7 @@ SELECT '' AS "48", d1 FROM TIMESTAMPTZ_TBL | Mon Feb 10 17:32:01 1997 PST | Mon Feb 10 17:32:01 1997 PST | Tue Jun 10 17:32:01 1997 PDT - | Sat Sep 22 11:19:20 2001 PDT + | Sat Sep 22 18:19:20 2001 PDT | Wed Mar 15 08:14:01 2000 PST | Wed Mar 15 04:14:02 2000 PST | Wed Mar 15 02:14:03 2000 PST @@ -304,7 +304,7 @@ SELECT '' AS "63", d1 FROM TIMESTAMPTZ_TBL | Mon Feb 10 17:32:01 1997 PST | Mon Feb 10 17:32:01 1997 PST | Tue Jun 10 17:32:01 1997 PDT - | Sat Sep 22 11:19:20 2001 PDT + | Sat Sep 22 18:19:20 2001 PDT | Wed Mar 15 08:14:01 2000 PST | Wed Mar 15 04:14:02 2000 PST | Wed Mar 15 02:14:03 2000 PST @@ -394,7 +394,7 @@ SELECT '' AS "49", d1 FROM TIMESTAMPTZ_TBL | Mon Feb 10 17:32:01 1997 PST | Mon Feb 10 17:32:01 1997 PST | Tue Jun 10 17:32:01 1997 PDT - | Sat Sep 22 11:19:20 2001 PDT + | Sat Sep 22 18:19:20 2001 PDT | Wed Mar 15 08:14:01 2000 PST | Wed Mar 15 04:14:02 2000 PST | Wed Mar 15 02:14:03 2000 PST @@ -449,7 +449,7 @@ SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff | @ 39 days 17 hours 32 mins 1 sec | @ 39 days 17 hours 32 mins 1 sec | @ 159 days 16 hours 32 mins 1 sec - | @ 1724 days 10 hours 19 mins 20 secs + | @ 1724 days 17 hours 19 mins 20 secs | @ 1168 days 8 hours 14 mins 1 sec | @ 1168 days 4 hours 14 mins 2 secs | @ 1168 days 2 hours 14 mins 3 secs @@ -511,7 +511,7 @@ SELECT '' AS "54", d1 - timestamp with time zone '1997-01-02' AS diff | @ 39 days 17 hours 32 mins 1 sec | @ 39 days 17 hours 32 mins 1 sec | @ 159 days 16 hours 32 mins 1 sec - | @ 1724 days 10 hours 19 mins 20 secs + | @ 1724 days 17 hours 19 mins 20 secs | @ 1168 days 8 hours 14 mins 1 sec | @ 1168 days 4 hours 14 mins 2 secs | @ 1168 days 2 hours 14 mins 3 secs @@ -574,7 +574,7 @@ SELECT '' AS "54", d1 as timestamptz, | Mon Feb 10 17:32:01 1997 PST | 1997 | 2 | 10 | 17 | 32 | 1 | Mon Feb 10 17:32:01 1997 PST | 1997 | 2 | 10 | 17 | 32 | 1 | Tue Jun 10 17:32:01 1997 PDT | 1997 | 6 | 10 | 17 | 32 | 1 - | Sat Sep 22 11:19:20 2001 PDT | 2001 | 9 | 22 | 11 | 19 | 20 + | Sat Sep 22 18:19:20 2001 PDT | 2001 | 9 | 22 | 18 | 19 | 20 | Wed Mar 15 08:14:01 2000 PST | 2000 | 3 | 15 | 8 | 14 | 1 | Wed Mar 15 04:14:02 2000 PST | 2000 | 3 | 15 | 4 | 14 | 2 | Wed Mar 15 02:14:03 2000 PST | 2000 | 3 | 15 | 2 | 14 | 3 @@ -636,7 +636,7 @@ SELECT '' AS "54", d1 as timestamptz, | Mon Feb 10 17:32:01 1997 PST | 1 | 0 | 0 | Mon Feb 10 17:32:01 1997 PST | 1 | 0 | 0 | Tue Jun 10 17:32:01 1997 PDT | 2 | 0 | 0 - | Sat Sep 22 11:19:20 2001 PDT | 3 | 0 | 0 + | Sat Sep 22 18:19:20 2001 PDT | 3 | 0 | 0 | Wed Mar 15 08:14:01 2000 PST | 1 | 0 | 0 | Wed Mar 15 04:14:02 2000 PST | 1 | 0 | 0 | Wed Mar 15 02:14:03 2000 PST | 1 | 0 | 0 @@ -982,7 +982,7 @@ SELECT '' AS to_char_5, to_char(d1, 'HH HH12 HH24 MI SS SSSS') | 05 05 17 32 01 63121 | 05 05 17 32 01 63121 | 05 05 17 32 01 63121 - | 11 11 11 19 20 40760 + | 06 06 18 19 20 65960 | 08 08 08 14 01 29641 | 04 04 04 14 02 15242 | 02 02 02 14 03 8043 @@ -1052,7 +1052,7 @@ SELECT '' AS to_char_6, to_char(d1, '"HH:MI:SS is" HH:MI:SS "\\"text between quo | HH:MI:SS is 05:32:01 "text between quote marks" | HH:MI:SS is 05:32:01 "text between quote marks" | HH:MI:SS is 05:32:01 "text between quote marks" - | HH:MI:SS is 11:19:20 "text between quote marks" + | HH:MI:SS is 06:19:20 "text between quote marks" | HH:MI:SS is 08:14:01 "text between quote marks" | HH:MI:SS is 04:14:02 "text between quote marks" | HH:MI:SS is 02:14:03 "text between quote marks" @@ -1123,7 +1123,7 @@ SELECT '' AS to_char_7, to_char(d1, 'HH24--text--MI--text--SS') | 17--text--32--text--01 | 17--text--32--text--01 | 17--text--32--text--01 - | 11--text--19--text--20 + | 18--text--19--text--20 | 08--text--14--text--01 | 04--text--14--text--02 | 02--text--14--text--03 @@ -1264,7 +1264,7 @@ SELECT '' AS to_char_9, to_char(d1, 'YYYY A.D. YYYY a.d. YYYY bc HH:MI:SS P.M. H | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm | 1997 A.D. 1997 a.d. 1997 ad 05:32:01 P.M. 05:32:01 p.m. 05:32:01 pm - | 2001 A.D. 2001 a.d. 2001 ad 11:19:20 A.M. 11:19:20 a.m. 11:19:20 am + | 2001 A.D. 2001 a.d. 2001 ad 06:19:20 P.M. 06:19:20 p.m. 06:19:20 pm | 2000 A.D. 2000 a.d. 2000 ad 08:14:01 A.M. 08:14:01 a.m. 08:14:01 am | 2000 A.D. 2000 a.d. 2000 ad 04:14:02 A.M. 04:14:02 a.m. 04:14:02 am | 2000 A.D. 2000 a.d. 2000 ad 02:14:03 A.M. 02:14:03 a.m. 02:14:03 am