]> granicus.if.org Git - postgresql/commitdiff
Repair two recently reported problems:
authorThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 4 Jan 2000 07:53:27 +0000 (07:53 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 4 Jan 2000 07:53:27 +0000 (07:53 +0000)
1) datetime_pl_span() added the seconds field before adding the months
 field.  This lead to erroneous results for e.g.
   select datetime '1999-11-30' + timespan '1 mon - 1 sec';
 Reverse the order of operations to add months first.
2) tm2timespan() did all intermediate math as integer, converting to double
 at the very end. This resulted in hidden overflows when given very large
 integer days, hours, etc. For example,
   select '74565 days'::timespan;
 produced the wrong result. Change code to ensure that doubles are used
 for intermediate calculations.
Thanks to Olivier PRENANT <ohp@pyrenet.fr> and
 Tulassay Zsolt <zsolt@tek.bke.hu> for problem reports and to Tom Lane for
 accurate analyses.

src/backend/utils/adt/dt.c

index bab4873fc1fef929817e46438381fc06a9a8c4de..a9ae4eebe379bd784298886e27f22b1f9c2344e0 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.79 2000/01/02 02:32:37 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.80 2000/01/04 07:53:27 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -787,6 +787,7 @@ datetime_mi(DateTime *datetime1, DateTime *datetime2)
  * To add a month, increment the month, and use the same day of month.
  * Then, if the next month has fewer days, set the day of month
  *     to the last day of month.
+ * Lastly, add in the "quantitative time".
  */
 DateTime   *
 datetime_pl_span(DateTime *datetime, TimeSpan *span)
@@ -815,12 +816,6 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
        {
                dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
 
-#ifdef ROUND_ALL
-               dt = JROUND(dt + span->time);
-#else
-               dt += span->time;
-#endif
-
                if (span->month != 0)
                {
                        struct tm       tt,
@@ -853,6 +848,12 @@ datetime_pl_span(DateTime *datetime, TimeSpan *span)
                                DATETIME_INVALID(dt);
                }
 
+#ifdef ROUND_ALL
+               dt = JROUND(dt + span->time);
+#else
+               dt += span->time;
+#endif
+
                *result = dt;
        }
 
@@ -2441,7 +2442,10 @@ static int
 tm2timespan(struct tm * tm, double fsec, TimeSpan *span)
 {
        span->month = ((tm->tm_year * 12) + tm->tm_mon);
-       span->time = ((((((tm->tm_mday * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60) + tm->tm_sec);
+       span->time = ((((((tm->tm_mday * 24.0)
+                                        + tm->tm_hour) * 60.0)
+                                        + tm->tm_min) * 60.0)
+                                        + tm->tm_sec);
        span->time = JROUND(span->time + fsec);
 
        return 0;