]> granicus.if.org Git - postgresql/commitdiff
Fix interval input parser so that fractional weeks and months are
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 4 Sep 2006 01:26:28 +0000 (01:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 4 Sep 2006 01:26:28 +0000 (01:26 +0000)
cascaded first to days and only what is leftover into seconds.  This
seems to satisfy the principle of least surprise given the general
conversion to three-part interval values --- it was an oversight that
these cases weren't dealt with in 8.1.  Michael Glaesemann

src/backend/utils/adt/datetime.c
src/interfaces/ecpg/pgtypeslib/interval.c
src/test/regress/expected/interval.out
src/test/regress/sql/interval.sql

index f4aceed0aa3fad85b14e3e7c90e6142586318c14..ab0a3b4e89e27143d11081d424c957d3aa0d6fa3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.169 2006/07/25 03:51:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.170 2006/09/04 01:26:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2920,16 +2920,23 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
                                                tm->tm_mday += val * 7;
                                                if (fval != 0)
                                                {
-                                                       int                     sec;
-
-                                                       fval *= 7 * SECS_PER_DAY;
-                                                       sec = fval;
-                                                       tm->tm_sec += sec;
+                                                       int extra_days;
+                                                       fval *= 7;
+                                                       extra_days = (int32) fval;
+                                                       tm->tm_mday += extra_days;
+                                                       fval -= extra_days;
+                                                       if (fval != 0)
+                                                       {
+                                                               int                     sec;
+                                                               fval *= SECS_PER_DAY;
+                                                               sec = fval;
+                                                               tm->tm_sec += sec;
 #ifdef HAVE_INT64_TIMESTAMP
-                                                       *fsec += (fval - sec) * 1000000;
+                                                               *fsec += (fval - sec) * 1000000;
 #else
-                                                       *fsec += fval - sec;
+                                                               *fsec += fval - sec;
 #endif
+                                                       }
                                                }
                                                tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
                                                break;
@@ -2938,16 +2945,23 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm,
                                                tm->tm_mon += val;
                                                if (fval != 0)
                                                {
-                                                       int                     sec;
-
-                                                       fval *= DAYS_PER_MONTH * SECS_PER_DAY;
-                                                       sec = fval;
-                                                       tm->tm_sec += sec;
+                                                       int         day;
+                                                       fval *= DAYS_PER_MONTH;
+                                                       day = fval;
+                                                       tm->tm_mday += day;
+                                                       fval -= day;
+                                                       if (fval != 0)
+                                                       {
+                                                               int                     sec;
+                                                               fval *= SECS_PER_DAY;
+                                                               sec = fval;
+                                                               tm->tm_sec += sec;
 #ifdef HAVE_INT64_TIMESTAMP
-                                                       *fsec += (fval - sec) * 1000000;
+                                                               *fsec += (fval - sec) * 1000000;
 #else
-                                                       *fsec += fval - sec;
+                                                               *fsec += fval - sec;
 #endif
+                                                       }
                                                }
                                                tmask = DTK_M(MONTH);
                                                break;
index b6d9b19b645d6b355542f0d035867f21e629b819..22643dbd966d114cea02c2c42a163ef60ed8debd 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.32 2006/06/06 11:31:55 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/interval.c,v 1.33 2006/09/04 01:26:28 tgl Exp $ */
 
 #include "postgres_fe.h"
 #include <time.h>
@@ -307,16 +307,23 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                                                tm->tm_mday += val * 7;
                                                if (fval != 0)
                                                {
-                                                       int                     sec;
-
-                                                       fval *= 7 * SECS_PER_DAY;
-                                                       sec = fval;
-                                                       tm->tm_sec += sec;
+                                                       int extra_days;
+                                                       fval *= 7;
+                                                       extra_days = (int32) fval;
+                                                       tm->tm_mday += extra_days;
+                                                       fval -= extra_days;
+                                                       if (fval != 0)
+                                                       {
+                                                               int                     sec;
+                                                               fval *= SECS_PER_DAY;
+                                                               sec = fval;
+                                                               tm->tm_sec += sec;
 #ifdef HAVE_INT64_TIMESTAMP
-                                                       *fsec += (fval - sec) * 1000000;
+                                                               *fsec += (fval - sec) * 1000000;
 #else
-                                                       *fsec += fval - sec;
+                                                               *fsec += fval - sec;
 #endif
+                                                       }
                                                }
                                                tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
                                                break;
@@ -325,16 +332,23 @@ DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fse
                                                tm->tm_mon += val;
                                                if (fval != 0)
                                                {
-                                                       int                     sec;
-
-                                                       fval *= DAYS_PER_MONTH * SECS_PER_DAY;
-                                                       sec = fval;
-                                                       tm->tm_sec += sec;
+                                                       int         day;
+                                                       fval *= DAYS_PER_MONTH;
+                                                       day = fval;
+                                                       tm->tm_mday += day;
+                                                       fval -= day;
+                                                       if (fval != 0)
+                                                       {
+                                                               int                     sec;
+                                                               fval *= SECS_PER_DAY;
+                                                               sec = fval;
+                                                               tm->tm_sec += sec;
 #ifdef HAVE_INT64_TIMESTAMP
-                                                       *fsec += (fval - sec) * 1000000;
+                                                               *fsec += (fval - sec) * 1000000;
 #else
-                                                       *fsec += fval - sec;
+                                                               *fsec += fval - sec;
 #endif
+                                                       }
                                                }
                                                tmask = DTK_M(MONTH);
                                                break;
index 0adda4a981d26e5f05fb01183a1b9dab960d361d..3a5fb12cbc317e8039cdf78f67c6a9518048300f 100644 (file)
@@ -39,6 +39,18 @@ SELECT INTERVAL '-1 days +02:03' AS "22 hours ago...";
  -1 days +02:03:00
 (1 row)
 
+SELECT INTERVAL '1.5 weeks' AS "Ten days twelve hours";
+ Ten days twelve hours 
+-----------------------
+ 10 days 12:00:00
+(1 row)
+
+SELECT INTERVAL '1.5 months' AS "One month 15 days";
+ One month 15 days 
+-------------------
+ 1 mon 15 days
+(1 row)
+
 SELECT INTERVAL '10 years -11 month -12 days +13:14' AS "9 years...";
             9 years...            
 ----------------------------------
index bc384d012120441a155b6b8c4363e89849a3f50d..f38b01e45dc00a6d12c63a9eb1cd0b1dfbce80c8 100644 (file)
@@ -11,6 +11,8 @@ SELECT INTERVAL '-08:00' AS "Eight hours";
 SELECT INTERVAL '-05' AS "Five hours";
 SELECT INTERVAL '-1 +02:03' AS "22 hours ago...";
 SELECT INTERVAL '-1 days +02:03' AS "22 hours ago...";
+SELECT INTERVAL '1.5 weeks' AS "Ten days twelve hours";
+SELECT INTERVAL '1.5 months' AS "One month 15 days";
 SELECT INTERVAL '10 years -11 month -12 days +13:14' AS "9 years...";
 
 CREATE TABLE INTERVAL_TBL (f1 interval);