Repair array subscript overrun identified by Yichen Xie. Reduce the
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jan 2003 01:08:42 +0000 (01:08 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 29 Jan 2003 01:08:42 +0000 (01:08 +0000)
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.)

doc/src/sgml/datatype.sgml
src/backend/utils/adt/date.c
src/backend/utils/adt/datetime.c
src/include/utils/date.h

index 3d75edca765400580e58bec1e8897d803e068ae6..9bbd5146c2a6c51589729e4b4343330a1efddc4b 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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">
@@ -1297,8 +1297,7 @@ SELECT b, char_length(b) FROM test2;
     fractional digits retained in the seconds field. By default, there
     is no explicit bound on precision.  The allowed range of
     <replaceable>p</replaceable> is from 0 to 6 for the
-    <type>timestamp</type> and <type>interval</type> types, 0 to 13
-    for the <type>time</type> types.
+    <type>timestamp</type> and <type>interval</type> types.
    </para>
 
    <note>
@@ -1314,6 +1313,12 @@ SELECT b, char_length(b) FROM test2;
    </para>
    </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>
     Time zones, and time-zone conventions, are influenced by
     political decisions, not just earth geometry. Time zones around the
@@ -1485,7 +1490,7 @@ SELECT b, char_length(b) FROM test2;
      <para>
       The <type>time</type> type can be specified as <type>time</type> or
       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.
      </para>
 
index 11a58b417460a7c5b3e318e5829b80c8b34d6c30..90f41ad817d557d2577588bc5ad6825ab69a4c3c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
 AdjustTimeForTypmod(TimeADT *time, int32 typmod)
 {
 #ifdef HAVE_INT64_TIMESTAMP
-   static const int64 TimeScales[MAX_TIMESTAMP_PRECISION + 1] = {
+   static const int64 TimeScales[MAX_TIME_PRECISION + 1] = {
        INT64CONST(1000000),
        INT64CONST(100000),
        INT64CONST(10000),
@@ -629,7 +629,7 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
        INT64CONST(1)
    };
 
-   static const int64 TimeOffsets[MAX_TIMESTAMP_PRECISION + 1] = {
+   static const int64 TimeOffsets[MAX_TIME_PRECISION + 1] = {
        INT64CONST(500000),
        INT64CONST(50000),
        INT64CONST(5000),
@@ -640,14 +640,19 @@ AdjustTimeForTypmod(TimeADT *time, int32 typmod)
    };
 
 #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,
        10,
        100,
        1000,
        10000,
        100000,
-       1000000
+       1000000,
+       10000000,
+       100000000,
+       1000000000,
+       10000000000
    };
 #endif
 
index 55e3e2a198450e770c4cbd3a1312e573c27c5b5b..b73554bf2e6433474b6c23c563f6ddb4530c3101 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
    }
 #endif
 
-   /* chop off trailing zeros... */
+   /* chop off trailing zeros... but leave at least 2 fractional digits */
    while ((*(str + len - 1) == '0')
           && (*(str + len - 3) != '.'))
    {
        len--;
        *(str + len) = '\0';
    }
-   return;
 }
 
 
@@ -3145,33 +3144,22 @@ EncodeDateOnly(struct tm * tm, int style, char *str)
 int
 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))
        return -1;
 
-#ifndef HAVE_INT64_TIMESTAMP
-   sec = (tm->tm_sec + fsec);
-#endif
-
    sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
 
    /*
-    * If we have fractional seconds, then include a decimal point We will
-    * do up to 6 fractional digits, and we have rounded any inputs to
-    * eliminate anything to the right of 6 digits anyway. If there are no
-    * fractional seconds, then do not bother printing a decimal point at
-    * all. - thomas 2001-09-29
+    * Print fractional seconds if any.  The field widths here should be
+    * at least equal to the larger of MAX_TIME_PRECISION and
+    * MAX_TIMESTAMP_PRECISION.
     */
    if (fsec != 0)
    {
 #ifdef HAVE_INT64_TIMESTAMP
-       sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-       sprintf((str + strlen(str)), ".%06d", fsec);
+       sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 #else
-       sprintf((str + strlen(str)), ":%013.10f", sec);
+       sprintf((str + strlen(str)), ":%013.10f", tm->tm_sec + fsec);
 #endif
        /* chop off trailing pairs of zeros... */
        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)
            *(str + strlen(str) - 2) = '\0';
    }
    else
-#ifdef HAVE_INT64_TIMESTAMP
        sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-#else
-       sprintf((str + strlen(str)), ":%02.0f", sec);
-#endif
 
    if (tzp != NULL)
    {
@@ -3217,20 +3201,12 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
                hour,
                min;
 
-#ifndef HAVE_INT64_TIMESTAMP
-   fsec_t      sec;
-#endif
-
    /*
     * 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((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
 
-#ifndef HAVE_INT64_TIMESTAMP
-   sec = (tm->tm_sec + fsec);
-#endif
-
    switch (style)
    {
        case USE_ISO_DATES:
@@ -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);
 
            /*
-            * If we have fractional seconds, then include a decimal point
-            * We will do up to 6 fractional digits, and we have rounded
-            * any inputs to eliminate anything to the right of 6 digits
-            * anyway. If there are no fractional seconds, then do not
-            * bother printing a decimal point at all. - thomas 2001-09-29
+            * Print fractional seconds if any.  The field widths here should
+            * be at least equal to MAX_TIMESTAMP_PRECISION.
+            *
+            * In float mode, don't print fractional seconds before 1 AD,
+            * since it's unlikely there's any precision left ...
             */
 #ifdef HAVE_INT64_TIMESTAMP
            if (fsec != 0)
            {
-               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-               sprintf((str + strlen(str)), ".%06d", fsec);
+               sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 #else
            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
                TrimTrailingZeros(str);
            }
@@ -3292,21 +3267,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
                    tm->tm_hour, tm->tm_min);
 
            /*
-            * If we have fractional seconds, then include a decimal point
-            * We will do up to 6 fractional digits, and we have rounded
-            * any inputs to eliminate anything to the right of 6 digits
-            * anyway. If there are no fractional seconds, then do not
-            * bother printing a decimal point at all. - thomas 2001-09-29
+            * Print fractional seconds if any.  The field widths here should
+            * be at least equal to MAX_TIMESTAMP_PRECISION.
+            *
+            * In float mode, don't print fractional seconds before 1 AD,
+            * since it's unlikely there's any precision left ...
             */
 #ifdef HAVE_INT64_TIMESTAMP
            if (fsec != 0)
            {
-               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-               sprintf((str + strlen(str)), ".%06d", fsec);
+               sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 #else
            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
                TrimTrailingZeros(str);
            }
@@ -3339,21 +3313,20 @@ EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, cha
                    tm->tm_hour, tm->tm_min);
 
            /*
-            * If we have fractional seconds, then include a decimal point
-            * We will do up to 6 fractional digits, and we have rounded
-            * any inputs to eliminate anything to the right of 6 digits
-            * anyway. If there are no fractional seconds, then do not
-            * bother printing a decimal point at all. - thomas 2001-09-29
+            * Print fractional seconds if any.  The field widths here should
+            * be at least equal to MAX_TIMESTAMP_PRECISION.
+            *
+            * In float mode, don't print fractional seconds before 1 AD,
+            * since it's unlikely there's any precision left ...
             */
 #ifdef HAVE_INT64_TIMESTAMP
            if (fsec != 0)
            {
-               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-               sprintf((str + strlen(str)), ".%06d", fsec);
+               sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 #else
            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
                TrimTrailingZeros(str);
            }
@@ -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);
 
            /*
-            * If we have fractional seconds, then include a decimal point
-            * We will do up to 6 fractional digits, and we have rounded
-            * any inputs to eliminate anything to the right of 6 digits
-            * anyway. If there are no fractional seconds, then do not
-            * bother printing a decimal point at all. - thomas 2001-09-29
+            * Print fractional seconds if any.  The field widths here should
+            * be at least equal to MAX_TIMESTAMP_PRECISION.
+            *
+            * In float mode, don't print fractional seconds before 1 AD,
+            * since it's unlikely there's any precision left ...
             */
 #ifdef HAVE_INT64_TIMESTAMP
            if (fsec != 0)
            {
-               sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
-               sprintf((str + strlen(str)), ".%06d", fsec);
+               sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 #else
            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
                TrimTrailingZeros(str);
            }
index eaaac77c16a34973b712096598950fa93d0f4aa7..cffa1d48749ac34604182e30297af8fb11323f34 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * 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
 #ifdef HAVE_INT64_TIMESTAMP
 #define MAX_TIME_PRECISION 6
 #else
-#define MAX_TIME_PRECISION 13
+#define MAX_TIME_PRECISION 10
 #endif
 
 /*