Re: [HACKERS] roundoff problem in time datatype - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] roundoff problem in time datatype
Date
Msg-id 200510140254.j9E2sVK16102@candle.pha.pa.us
Whole thread Raw
Responses Re: [HACKERS] roundoff problem in time datatype  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: [HACKERS] roundoff problem in time datatype  (Neil Conway <neilc@samurai.com>)
List pgsql-patches
I have written the attached patch which I think does what you suggested.
I found all the places where we disallowed 24:00:00, and make it valid,
including nabstime.c.

    test=>  select '24:00:00'::time(0);
       time
    ----------
     24:00:00
    (1 row)

    test=>  select '24:00:01'::time(0);
    ERROR:  date/time field value out of range: "24:00:01"

---------------------------------------------------------------------------

Tom Lane wrote:
> Inserting into a time field with limited precision rounds off, which
> is good except for this case:
>
> regression=# select '23:59:59.9'::time(0);
>    time
> ----------
>  24:00:00
> (1 row)
>
> This is bad because:
>
> regression=# select '24:00:00'::time(0);
> ERROR:  date/time field value out of range: "24:00:00"
>
> which means that data originally accepted will fail to dump and reload.
>
> I see this behavior in all versions back to 7.3.  7.2 was even more
> broken:
>
> regression=# select '23:59:59.9'::time(0);
>    time
> ----------
>  00:00:00
> (1 row)
>
> I think the correct behavior has to be to check for overflow again
> after rounding off.  Alternatively: why are we forbidding the value
> 24:00:00 anyway?  Is there a reason not to allow the hours field
> to exceed 23?
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: explain analyze is your friend
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/backend/utils/adt/datetime.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v
retrieving revision 1.158
diff -c -c -r1.158 datetime.c
*** src/backend/utils/adt/datetime.c    9 Oct 2005 17:21:46 -0000    1.158
--- src/backend/utils/adt/datetime.c    14 Oct 2005 02:52:39 -0000
***************
*** 1114,1120 ****
                   * Check upper limit on hours; other limits checked in
                   * DecodeTime()
                   */
!                 if (tm->tm_hour > 23)
                      return DTERR_FIELD_OVERFLOW;
                  break;

--- 1114,1122 ----
                   * Check upper limit on hours; other limits checked in
                   * DecodeTime()
                   */
!                 /* test for > 24:00:00 */
!                 if  (tm->tm_hour > 24 ||
!                      (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
                      return DTERR_FIELD_OVERFLOW;
                  break;

***************
*** 2243,2256 ****
      else if (mer == PM && tm->tm_hour != 12)
          tm->tm_hour += 12;

  #ifdef HAVE_INT64_TIMESTAMP
!     if (tm->tm_hour < 0 || tm->tm_hour > 23 || tm->tm_min < 0 ||
!         tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60 ||
          *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
          return DTERR_FIELD_OVERFLOW;
  #else
!     if (tm->tm_hour < 0 || tm->tm_hour > 23 || tm->tm_min < 0 ||
!         tm->tm_min > 59 || tm->tm_sec < 0 || tm->tm_sec > 60 ||
          *fsec < 0 || *fsec >= 1)
          return DTERR_FIELD_OVERFLOW;
  #endif
--- 2245,2260 ----
      else if (mer == PM && tm->tm_hour != 12)
          tm->tm_hour += 12;

+     if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
+         tm->tm_sec < 0 || tm->tm_sec > 60 || tm->tm_hour > 24 ||
+         /* Allow 24:00:00 */
+         (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0 ||
  #ifdef HAVE_INT64_TIMESTAMP
!         *fsec > INT64CONST(0))) ||
          *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
          return DTERR_FIELD_OVERFLOW;
  #else
!         *fsec > 0)) ||
          *fsec < 0 || *fsec >= 1)
          return DTERR_FIELD_OVERFLOW;
  #endif
Index: src/backend/utils/adt/nabstime.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v
retrieving revision 1.143
diff -c -c -r1.143 nabstime.c
*** src/backend/utils/adt/nabstime.c    24 Sep 2005 22:54:38 -0000    1.143
--- src/backend/utils/adt/nabstime.c    14 Oct 2005 02:52:40 -0000
***************
*** 187,193 ****
      if (tm->tm_year < 1901 || tm->tm_year > 2038
          || tm->tm_mon < 1 || tm->tm_mon > 12
          || tm->tm_mday < 1 || tm->tm_mday > 31
!         || tm->tm_hour < 0 || tm->tm_hour > 23
          || tm->tm_min < 0 || tm->tm_min > 59
          || tm->tm_sec < 0 || tm->tm_sec > 60)
          return INVALID_ABSTIME;
--- 187,195 ----
      if (tm->tm_year < 1901 || tm->tm_year > 2038
          || tm->tm_mon < 1 || tm->tm_mon > 12
          || tm->tm_mday < 1 || tm->tm_mday > 31
!         || tm->tm_hour < 0
!         || tm->tm_hour > 24    /* Allow 24:00:00 */
!         || (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0))
          || tm->tm_min < 0 || tm->tm_min > 59
          || tm->tm_sec < 0 || tm->tm_sec > 60)
          return INVALID_ABSTIME;
Index: src/interfaces/ecpg/pgtypeslib/dt_common.c
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/dt_common.c,v
retrieving revision 1.30
diff -c -c -r1.30 dt_common.c
*** src/interfaces/ecpg/pgtypeslib/dt_common.c    9 Oct 2005 17:21:45 -0000    1.30
--- src/interfaces/ecpg/pgtypeslib/dt_common.c    14 Oct 2005 02:52:41 -0000
***************
*** 2095,2101 ****
                   * Check upper limit on hours; other limits checked in
                   * DecodeTime()
                   */
!                 if (tm->tm_hour > 23)
                      return -1;
                  break;

--- 2095,2103 ----
                   * Check upper limit on hours; other limits checked in
                   * DecodeTime()
                   */
!                 /* test for > 24:00:00 */
!                 if  (tm->tm_hour > 24 ||
!                      (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
                      return -1;
                  break;

***************
*** 3161,3167 ****
              err = 1;
              *minute = 0;
          }
!         if (*hour > 23)
          {
              err = 1;
              *hour = 0;
--- 3163,3170 ----
              err = 1;
              *minute = 0;
          }
!         if (*hour > 24 ||
!             (*hour == 24 && (*minute > 0 || *second > 0)))
          {
              err = 1;
              *hour = 0;

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [BUGS] BUG #1962: ECPG and VARCHAR
Next
From: Tom Lane
Date:
Subject: Re: [HACKERS] roundoff problem in time datatype