Fix several places where fractional-second inputs were misprocessed

in HAVE_INT64_TIMESTAMP cases, including two potential stack smashes
when more than six fractional digits were supplied.  Per bug report
from Philipp Reisner.
This commit is contained in:
Tom Lane 2003-08-05 17:39:19 +00:00
parent b6f31f08dd
commit 9d41073f04

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.110 2003/08/04 02:40:04 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.111 2003/08/05 17:39:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1147,7 +1147,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
if (*cp != '\0') if (*cp != '\0')
return -1; return -1;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
*fsec = frac * 1000000; *fsec = rint(frac * 1000000);
#else #else
*fsec = frac; *fsec = frac;
#endif #endif
@ -1177,9 +1177,11 @@ DecodeDateTime(char **field, int *ftype, int nf,
tmask |= DTK_TIME_M; tmask |= DTK_TIME_M;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
dt2time((time * 86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); dt2time((time * 86400000000),
&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
#else #else
dt2time((time * 86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); dt2time((time * 86400),
&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
#endif #endif
} }
break; break;
@ -1882,9 +1884,16 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmask = DTK_M(SECOND); tmask = DTK_M(SECOND);
if (*cp == '.') if (*cp == '.')
{ {
*fsec = strtod(cp, &cp); double frac;
frac = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return -1;
#ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000);
#else
*fsec = frac;
#endif
} }
break; break;
@ -1910,9 +1919,11 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmask |= DTK_TIME_M; tmask |= DTK_TIME_M;
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
dt2time((time * 86400000000), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); dt2time((time * 86400000000),
&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
#else #else
dt2time((time * 86400), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec); dt2time((time * 86400),
&tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
#endif #endif
} }
break; break;
@ -2336,24 +2347,17 @@ DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec)
*fsec = 0; *fsec = 0;
else if (*cp == '.') else if (*cp == '.')
{ {
#ifdef HAVE_INT64_TIMESTAMP double frac;
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; str = cp;
*fsec = strtod(str, &cp); frac = strtod(str, &cp);
#endif
if (*cp != '\0') if (*cp != '\0')
return -1; return -1;
#ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000);
#else
*fsec = frac;
#endif
} }
else else
return -1; return -1;
@ -2396,6 +2400,8 @@ DecodeNumber(int flen, char *str, int fmask,
if (*cp == '.') if (*cp == '.')
{ {
double frac;
/* /*
* More than two digits before decimal point? Then could be a date * More than two digits before decimal point? Then could be a date
* or a run-together time: 2001.360 20011225 040506.789 * or a run-together time: 2001.360 20011225 040506.789
@ -2404,9 +2410,14 @@ DecodeNumber(int flen, char *str, int fmask,
return DecodeNumberField(flen, str, (fmask | DTK_DATE_M), return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
tmask, tm, fsec, is2digits); tmask, tm, fsec, is2digits);
*fsec = strtod(cp, &cp); frac = strtod(cp, &cp);
if (*cp != '\0') if (*cp != '\0')
return -1; return -1;
#ifdef HAVE_INT64_TIMESTAMP
*fsec = rint(frac * 1000000);
#else
*fsec = frac;
#endif
} }
else if (*cp != '\0') else if (*cp != '\0')
return -1; return -1;
@ -2514,19 +2525,13 @@ DecodeNumberField(int len, char *str, int fmask,
*/ */
if ((cp = strchr(str, '.')) != NULL) if ((cp = strchr(str, '.')) != NULL)
{ {
#ifdef HAVE_INT64_TIMESTAMP double frac;
char fstr[MAXDATELEN + 1];
/* frac = strtod(cp, NULL);
* OK, we have at most six digits to care about. Let's construct a #ifdef HAVE_INT64_TIMESTAMP
* string and then do the conversion to an integer. *fsec = rint(frac * 1000000);
*/
strcpy(fstr, (cp + 1));
strcpy((fstr + strlen(fstr)), "000000");
*(fstr + 6) = '\0';
*fsec = strtol(fstr, NULL, 10);
#else #else
*fsec = strtod(cp, NULL); *fsec = frac;
#endif #endif
*cp = '\0'; *cp = '\0';
len = strlen(str); len = strlen(str);