Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 23b8a0c

Browse files
committed
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.)
1 parent b8add56 commit 23b8a0c

File tree

4 files changed

+56
-74
lines changed

4 files changed

+56
-74
lines changed

doc/src/sgml/datatype.sgml

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.111 2003/01/15 18:01:04 momjian Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.112 2003/01/29 01:08:42 tgl Exp $
33
-->
44

55
<chapter id="datatype">
@@ -1297,8 +1297,7 @@ SELECT b, char_length(b) FROM test2;
12971297
fractional digits retained in the seconds field. By default, there
12981298
is no explicit bound on precision. The allowed range of
12991299
<replaceable>p</replaceable> is from 0 to 6 for the
1300-
<type>timestamp</type> and <type>interval</type> types, 0 to 13
1301-
for the <type>time</type> types.
1300+
<type>timestamp</type> and <type>interval</type> types.
13021301
</para>
13031302

13041303
<note>
@@ -1314,6 +1313,12 @@ SELECT b, char_length(b) FROM test2;
13141313
</para>
13151314
</note>
13161315

1316+
<para>
1317+
For the <type>time</type> types, the allowed range of
1318+
<replaceable>p</replaceable> is from 0 to 6 when eight-byte integer
1319+
storage is used, or from 0 to 10 when floating-point storage is used.
1320+
</para>
1321+
13171322
<para>
13181323
Time zones, and time-zone conventions, are influenced by
13191324
political decisions, not just earth geometry. Time zones around the
@@ -1485,7 +1490,7 @@ SELECT b, char_length(b) FROM test2;
14851490
<para>
14861491
The <type>time</type> type can be specified as <type>time</type> or
14871492
as <type>time without time zone</type>. The optional precision
1488-
<replaceable>p</replaceable> should be between 0 and 13, and
1493+
<replaceable>p</replaceable> should be between 0 and 6, and
14891494
defaults to the precision of the input time literal.
14901495
</para>
14911496

src/backend/utils/adt/date.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.76 2003/01/22 20:44:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.77 2003/01/29 01:08:42 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -619,7 +619,7 @@ static void
619619
AdjustTimeForTypmod(TimeADT *time, int32 typmod)
620620
{
621621
#ifdef HAVE_INT64_TIMESTAMP
622-
static const int64 TimeScales[MAX_TIMESTAMP_PRECISION + 1] = {
622+
static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
623623
INT64CONST(1000000),
624624
INT64CONST(100000),
625625
INT64CONST(10000),
@@ -629,7 +629,7 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
629629
INT64CONST(1)
630630
};
631631

632-
static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
632+
static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
633633
INT64CONST(500000),
634634
INT64CONST(50000),
635635
INT64CONST(5000),
@@ -640,14 +640,19 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
640640
};
641641

642642
#else
643-
static const double TimeScales[MAX_TIMESTAMP_PRECISION + 1] = {
643+
/* note MAX_TIME_PRECISION differs in this case */
644+
static const double TimeScales[MAX_TIME_PRECISION + 1] = {
644645
1,
645646
10,
646647
100,
647648
1000,
648649
10000,
649650
100000,
650-
1000000
651+
1000000,
652+
10000000,
653+
100000000,
654+
1000000000,
655+
10000000000
651656
};
652657
#endif
653658

src/backend/utils/adt/datetime.c

+35-63
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.98 2003/01/16 00:26:45 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.99 2003/01/29 01:08:42 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -667,14 +667,13 @@ TrimTrailingZeros(char *str)
667667
}
668668
#endif
669669

670-
/* chop off trailing zeros... */
670+
/* chop off trailing zeros... but leave at least 2 fractional digits */
671671
while ((*(str + len - 1) == '0')
672672
&& (*(str + len - 3) != '.'))
673673
{
674674
len--;
675675
*(str + len) = '\0';
676676
}
677-
return;
678677
}
679678

680679

@@ -3145,45 +3144,30 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
31453144
int
31463145
EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str)
31473146
{
3148-
#ifndef HAVE_INT64_TIMESTAMP
3149-
fsec_t sec;
3150-
#endif
3151-
31523147
if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
31533148
return -1;
31543149

3155-
#ifndef HAVE_INT64_TIMESTAMP
3156-
sec = (tm->tm_sec + fsec);
3157-
#endif
3158-
31593150
sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
31603151

31613152
/*
3162-
* If we have fractional seconds, then include a decimal point We will
3163-
* do up to 6 fractional digits, and we have rounded any inputs to
3164-
* eliminate anything to the right of 6 digits anyway. If there are no
3165-
* fractional seconds, then do not bother printing a decimal point at
3166-
* all. - thomas 2001-09-29
3153+
* Print fractional seconds if any. The field widths here should be
3154+
* at least equal to the larger of MAX_TIME_PRECISION and
3155+
* MAX_TIMESTAMP_PRECISION.
31673156
*/
31683157
if (fsec != 0)
31693158
{
31703159
#ifdef HAVE_INT64_TIMESTAMP
3171-
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3172-
sprintf((str + strlen(str)), ".%06d", fsec);
3160+
sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
31733161
#else
3174-
sprintf((str + strlen(str)), ":%013.10f", sec);
3162+
sprintf((str + strlen(str)), ":%013.10f", tm->tm_sec + fsec);
31753163
#endif
31763164
/* chop off trailing pairs of zeros... */
31773165
while ((strcmp((str + strlen(str) - 2), "00") == 0)
31783166
&& (*(str + strlen(str) - 3) != '.'))
31793167
*(str + strlen(str) - 2) = '\0';
31803168
}
31813169
else
3182-
#ifdef HAVE_INT64_TIMESTAMP
31833170
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3184-
#else
3185-
sprintf((str + strlen(str)), ":%02.0f", sec);
3186-
#endif
31873171

31883172
if (tzp != NULL)
31893173
{
@@ -3217,20 +3201,12 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
32173201
hour,
32183202
min;
32193203

3220-
#ifndef HAVE_INT64_TIMESTAMP
3221-
fsec_t sec;
3222-
#endif
3223-
32243204
/*
32253205
* Why are we checking only the month field? Change this to an
32263206
* assert... if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) return -1;
32273207
*/
32283208
Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
32293209

3230-
#ifndef HAVE_INT64_TIMESTAMP
3231-
sec = (tm->tm_sec + fsec);
3232-
#endif
3233-
32343210
switch (style)
32353211
{
32363212
case USE_ISO_DATES:
@@ -3241,21 +3217,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
32413217
tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
32423218

32433219
/*
3244-
* If we have fractional seconds, then include a decimal point
3245-
* We will do up to 6 fractional digits, and we have rounded
3246-
* any inputs to eliminate anything to the right of 6 digits
3247-
* anyway. If there are no fractional seconds, then do not
3248-
* bother printing a decimal point at all. - thomas 2001-09-29
3220+
* Print fractional seconds if any. The field widths here should
3221+
* be at least equal to MAX_TIMESTAMP_PRECISION.
3222+
*
3223+
* In float mode, don't print fractional seconds before 1 AD,
3224+
* since it's unlikely there's any precision left ...
32493225
*/
32503226
#ifdef HAVE_INT64_TIMESTAMP
32513227
if (fsec != 0)
32523228
{
3253-
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3254-
sprintf((str + strlen(str)), ".%06d", fsec);
3229+
sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
32553230
#else
32563231
if ((fsec != 0) && (tm->tm_year > 0))
32573232
{
3258-
sprintf((str + strlen(str)), ":%013.10f", sec);
3233+
sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
32593234
#endif
32603235
TrimTrailingZeros(str);
32613236
}
@@ -3292,21 +3267,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
32923267
tm->tm_hour, tm->tm_min);
32933268

32943269
/*
3295-
* If we have fractional seconds, then include a decimal point
3296-
* We will do up to 6 fractional digits, and we have rounded
3297-
* any inputs to eliminate anything to the right of 6 digits
3298-
* anyway. If there are no fractional seconds, then do not
3299-
* bother printing a decimal point at all. - thomas 2001-09-29
3270+
* Print fractional seconds if any. The field widths here should
3271+
* be at least equal to MAX_TIMESTAMP_PRECISION.
3272+
*
3273+
* In float mode, don't print fractional seconds before 1 AD,
3274+
* since it's unlikely there's any precision left ...
33003275
*/
33013276
#ifdef HAVE_INT64_TIMESTAMP
33023277
if (fsec != 0)
33033278
{
3304-
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3305-
sprintf((str + strlen(str)), ".%06d", fsec);
3279+
sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
33063280
#else
33073281
if ((fsec != 0) && (tm->tm_year > 0))
33083282
{
3309-
sprintf((str + strlen(str)), ":%013.10f", sec);
3283+
sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
33103284
#endif
33113285
TrimTrailingZeros(str);
33123286
}
@@ -3339,21 +3313,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
33393313
tm->tm_hour, tm->tm_min);
33403314

33413315
/*
3342-
* If we have fractional seconds, then include a decimal point
3343-
* We will do up to 6 fractional digits, and we have rounded
3344-
* any inputs to eliminate anything to the right of 6 digits
3345-
* anyway. If there are no fractional seconds, then do not
3346-
* bother printing a decimal point at all. - thomas 2001-09-29
3316+
* Print fractional seconds if any. The field widths here should
3317+
* be at least equal to MAX_TIMESTAMP_PRECISION.
3318+
*
3319+
* In float mode, don't print fractional seconds before 1 AD,
3320+
* since it's unlikely there's any precision left ...
33473321
*/
33483322
#ifdef HAVE_INT64_TIMESTAMP
33493323
if (fsec != 0)
33503324
{
3351-
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3352-
sprintf((str + strlen(str)), ".%06d", fsec);
3325+
sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
33533326
#else
33543327
if ((fsec != 0) && (tm->tm_year > 0))
33553328
{
3356-
sprintf((str + strlen(str)), ":%013.10f", sec);
3329+
sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
33573330
#endif
33583331
TrimTrailingZeros(str);
33593332
}
@@ -3394,21 +3367,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
33943367
sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
33953368

33963369
/*
3397-
* If we have fractional seconds, then include a decimal point
3398-
* We will do up to 6 fractional digits, and we have rounded
3399-
* any inputs to eliminate anything to the right of 6 digits
3400-
* anyway. If there are no fractional seconds, then do not
3401-
* bother printing a decimal point at all. - thomas 2001-09-29
3370+
* Print fractional seconds if any. The field widths here should
3371+
* be at least equal to MAX_TIMESTAMP_PRECISION.
3372+
*
3373+
* In float mode, don't print fractional seconds before 1 AD,
3374+
* since it's unlikely there's any precision left ...
34023375
*/
34033376
#ifdef HAVE_INT64_TIMESTAMP
34043377
if (fsec != 0)
34053378
{
3406-
sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
3407-
sprintf((str + strlen(str)), ".%06d", fsec);
3379+
sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
34083380
#else
34093381
if ((fsec != 0) && (tm->tm_year > 0))
34103382
{
3411-
sprintf((str + strlen(str)), ":%013.10f", sec);
3383+
sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
34123384
#endif
34133385
TrimTrailingZeros(str);
34143386
}

src/include/utils/date.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: date.h,v 1.21 2002/09/04 20:31:45 momjian Exp $
10+
* $Id: date.h,v 1.22 2003/01/29 01:08:42 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -41,7 +41,7 @@ typedef struct
4141
#ifdef HAVE_INT64_TIMESTAMP
4242
#define MAX_TIME_PRECISION 6
4343
#else
44-
#define MAX_TIME_PRECISION 13
44+
#define MAX_TIME_PRECISION 10
4545
#endif
4646

4747
/*

0 commit comments

Comments
 (0)