Commit 23b8a0ce authored by Tom Lane's avatar Tom Lane

Repair array subscript overrun identified by Yichen Xie. Reduce the

value of MAX_TIME_PRECISION in floating-point-timestamp-storage case
from 13 to 10, which is as much as time_out is actually willing to print.
(The alternative of increasing the number of digits we are willing to
print looks risky; we might find ourselves printing roundoff garbage.)
parent b8add56e
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.111 2003/01/15 18:01:04 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.112 2003/01/29 01:08:42 tgl Exp $
--> -->
<chapter id="datatype"> <chapter id="datatype">
...@@ -1297,8 +1297,7 @@ SELECT b, char_length(b) FROM test2; ...@@ -1297,8 +1297,7 @@ SELECT b, char_length(b) FROM test2;
fractional digits retained in the seconds field. By default, there fractional digits retained in the seconds field. By default, there
is no explicit bound on precision. The allowed range of is no explicit bound on precision. The allowed range of
<replaceable>p</replaceable> is from 0 to 6 for the <replaceable>p</replaceable> is from 0 to 6 for the
<type>timestamp</type> and <type>interval</type> types, 0 to 13 <type>timestamp</type> and <type>interval</type> types.
for the <type>time</type> types.
</para> </para>
<note> <note>
...@@ -1314,6 +1313,12 @@ SELECT b, char_length(b) FROM test2; ...@@ -1314,6 +1313,12 @@ SELECT b, char_length(b) FROM test2;
</para> </para>
</note> </note>
<para>
For the <type>time</type> types, the allowed range of
<replaceable>p</replaceable> is from 0 to 6 when eight-byte integer
storage is used, or from 0 to 10 when floating-point storage is used.
</para>
<para> <para>
Time zones, and time-zone conventions, are influenced by Time zones, and time-zone conventions, are influenced by
political decisions, not just earth geometry. Time zones around the political decisions, not just earth geometry. Time zones around the
...@@ -1485,7 +1490,7 @@ SELECT b, char_length(b) FROM test2; ...@@ -1485,7 +1490,7 @@ SELECT b, char_length(b) FROM test2;
<para> <para>
The <type>time</type> type can be specified as <type>time</type> or The <type>time</type> type can be specified as <type>time</type> or
as <type>time without time zone</type>. The optional precision as <type>time without time zone</type>. The optional precision
<replaceable>p</replaceable> should be between 0 and 13, and <replaceable>p</replaceable> should be between 0 and 6, and
defaults to the precision of the input time literal. defaults to the precision of the input time literal.
</para> </para>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.76 2003/01/22 20:44:20 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.77 2003/01/29 01:08:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -619,7 +619,7 @@ static void ...@@ -619,7 +619,7 @@ static void
AdjustTimeForTypmod(TimeADT *time, int32 typmod) AdjustTimeForTypmod(TimeADT *time, int32 typmod)
{ {
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
static const int64 TimeScales[MAX_TIMESTAMP_PRECISION + 1] = { static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
INT64CONST(1000000), INT64CONST(1000000),
INT64CONST(100000), INT64CONST(100000),
INT64CONST(10000), INT64CONST(10000),
...@@ -629,7 +629,7 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod) ...@@ -629,7 +629,7 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
INT64CONST(1) INT64CONST(1)
}; };
static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION + 1] = { static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
INT64CONST(500000), INT64CONST(500000),
INT64CONST(50000), INT64CONST(50000),
INT64CONST(5000), INT64CONST(5000),
...@@ -640,14 +640,19 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod) ...@@ -640,14 +640,19 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
}; };
#else #else
static const double TimeScales[MAX_TIMESTAMP_PRECISION + 1] = { /* note MAX_TIME_PRECISION differs in this case */
static const double TimeScales[MAX_TIME_PRECISION + 1] = {
1, 1,
10, 10,
100, 100,
1000, 1000,
10000, 10000,
100000, 100000,
1000000 1000000,
10000000,
100000000,
1000000000,
10000000000
}; };
#endif #endif
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.98 2003/01/16 00:26:45 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.99 2003/01/29 01:08:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -667,14 +667,13 @@ TrimTrailingZeros(char *str) ...@@ -667,14 +667,13 @@ TrimTrailingZeros(char *str)
} }
#endif #endif
/* chop off trailing zeros... */ /* chop off trailing zeros... but leave at least 2 fractional digits */
while ((*(str + len - 1) == '0') while ((*(str + len - 1) == '0')
&& (*(str + len - 3) != '.')) && (*(str + len - 3) != '.'))
{ {
len--; len--;
*(str + len) = '\0'; *(str + len) = '\0';
} }
return;
} }
...@@ -3145,33 +3144,22 @@ EncodeDateOnly(struct tm * tm, int style, char *str) ...@@ -3145,33 +3144,22 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
int int
EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str) EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str)
{ {
#ifndef HAVE_INT64_TIMESTAMP
fsec_t sec;
#endif
if ((tm->tm_hour < 0) || (tm->tm_hour > 24)) if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
return -1; return -1;
#ifndef HAVE_INT64_TIMESTAMP
sec = (tm->tm_sec + fsec);
#endif
sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min); sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
/* /*
* If we have fractional seconds, then include a decimal point We will * Print fractional seconds if any. The field widths here should be
* do up to 6 fractional digits, and we have rounded any inputs to * at least equal to the larger of MAX_TIME_PRECISION and
* eliminate anything to the right of 6 digits anyway. If there are no * MAX_TIMESTAMP_PRECISION.
* fractional seconds, then do not bother printing a decimal point at
* all. - thomas 2001-09-29
*/ */
if (fsec != 0) if (fsec != 0)
{ {
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
sprintf((str + strlen(str)), ".%06d", fsec);
#else #else
sprintf((str + strlen(str)), ":%013.10f", sec); sprintf((str + strlen(str)), ":%013.10f", tm->tm_sec + fsec);
#endif #endif
/* chop off trailing pairs of zeros... */ /* chop off trailing pairs of zeros... */
while ((strcmp((str + strlen(str) - 2), "00") == 0) while ((strcmp((str + strlen(str) - 2), "00") == 0)
...@@ -3179,11 +3167,7 @@ EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str) ...@@ -3179,11 +3167,7 @@ EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str)
*(str + strlen(str) - 2) = '\0'; *(str + strlen(str) - 2) = '\0';
} }
else else
#ifdef HAVE_INT64_TIMESTAMP
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
#else
sprintf((str + strlen(str)), ":%02.0f", sec);
#endif
if (tzp != NULL) if (tzp != NULL)
{ {
...@@ -3217,20 +3201,12 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha ...@@ -3217,20 +3201,12 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
hour, hour,
min; min;
#ifndef HAVE_INT64_TIMESTAMP
fsec_t sec;
#endif
/* /*
* Why are we checking only the month field? Change this to an * 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... if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) return -1;
*/ */
Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12)); Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
#ifndef HAVE_INT64_TIMESTAMP
sec = (tm->tm_sec + fsec);
#endif
switch (style) switch (style)
{ {
case USE_ISO_DATES: case USE_ISO_DATES:
...@@ -3241,21 +3217,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha ...@@ -3241,21 +3217,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min); tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
/* /*
* If we have fractional seconds, then include a decimal point * Print fractional seconds if any. The field widths here should
* We will do up to 6 fractional digits, and we have rounded * be at least equal to MAX_TIMESTAMP_PRECISION.
* any inputs to eliminate anything to the right of 6 digits *
* anyway. If there are no fractional seconds, then do not * In float mode, don't print fractional seconds before 1 AD,
* bother printing a decimal point at all. - thomas 2001-09-29 * since it's unlikely there's any precision left ...
*/ */
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
if (fsec != 0) if (fsec != 0)
{ {
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
sprintf((str + strlen(str)), ".%06d", fsec);
#else #else
if ((fsec != 0) && (tm->tm_year > 0)) if ((fsec != 0) && (tm->tm_year > 0))
{ {
sprintf((str + strlen(str)), ":%013.10f", sec); sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
#endif #endif
TrimTrailingZeros(str); TrimTrailingZeros(str);
} }
...@@ -3292,21 +3267,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha ...@@ -3292,21 +3267,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
tm->tm_hour, tm->tm_min); tm->tm_hour, tm->tm_min);
/* /*
* If we have fractional seconds, then include a decimal point * Print fractional seconds if any. The field widths here should
* We will do up to 6 fractional digits, and we have rounded * be at least equal to MAX_TIMESTAMP_PRECISION.
* any inputs to eliminate anything to the right of 6 digits *
* anyway. If there are no fractional seconds, then do not * In float mode, don't print fractional seconds before 1 AD,
* bother printing a decimal point at all. - thomas 2001-09-29 * since it's unlikely there's any precision left ...
*/ */
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
if (fsec != 0) if (fsec != 0)
{ {
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
sprintf((str + strlen(str)), ".%06d", fsec);
#else #else
if ((fsec != 0) && (tm->tm_year > 0)) if ((fsec != 0) && (tm->tm_year > 0))
{ {
sprintf((str + strlen(str)), ":%013.10f", sec); sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
#endif #endif
TrimTrailingZeros(str); TrimTrailingZeros(str);
} }
...@@ -3339,21 +3313,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha ...@@ -3339,21 +3313,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
tm->tm_hour, tm->tm_min); tm->tm_hour, tm->tm_min);
/* /*
* If we have fractional seconds, then include a decimal point * Print fractional seconds if any. The field widths here should
* We will do up to 6 fractional digits, and we have rounded * be at least equal to MAX_TIMESTAMP_PRECISION.
* any inputs to eliminate anything to the right of 6 digits *
* anyway. If there are no fractional seconds, then do not * In float mode, don't print fractional seconds before 1 AD,
* bother printing a decimal point at all. - thomas 2001-09-29 * since it's unlikely there's any precision left ...
*/ */
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
if (fsec != 0) if (fsec != 0)
{ {
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
sprintf((str + strlen(str)), ".%06d", fsec);
#else #else
if ((fsec != 0) && (tm->tm_year > 0)) if ((fsec != 0) && (tm->tm_year > 0))
{ {
sprintf((str + strlen(str)), ":%013.10f", sec); sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
#endif #endif
TrimTrailingZeros(str); TrimTrailingZeros(str);
} }
...@@ -3394,21 +3367,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha ...@@ -3394,21 +3367,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
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 * Print fractional seconds if any. The field widths here should
* We will do up to 6 fractional digits, and we have rounded * be at least equal to MAX_TIMESTAMP_PRECISION.
* any inputs to eliminate anything to the right of 6 digits *
* anyway. If there are no fractional seconds, then do not * In float mode, don't print fractional seconds before 1 AD,
* bother printing a decimal point at all. - thomas 2001-09-29 * since it's unlikely there's any precision left ...
*/ */
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
if (fsec != 0) if (fsec != 0)
{ {
sprintf((str + strlen(str)), ":%02d", tm->tm_sec); sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
sprintf((str + strlen(str)), ".%06d", fsec);
#else #else
if ((fsec != 0) && (tm->tm_year > 0)) if ((fsec != 0) && (tm->tm_year > 0))
{ {
sprintf((str + strlen(str)), ":%013.10f", sec); sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
#endif #endif
TrimTrailingZeros(str); TrimTrailingZeros(str);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: date.h,v 1.21 2002/09/04 20:31:45 momjian Exp $ * $Id: date.h,v 1.22 2003/01/29 01:08:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -41,7 +41,7 @@ typedef struct ...@@ -41,7 +41,7 @@ typedef struct
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
#define MAX_TIME_PRECISION 6 #define MAX_TIME_PRECISION 6
#else #else
#define MAX_TIME_PRECISION 13 #define MAX_TIME_PRECISION 10
#endif #endif
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment