Re: Interval month, week -> day - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Interval month, week -> day
Date
Msg-id 200608300422.k7U4M5x14509@momjian.us
Whole thread Raw
In response to Interval month, week -> day  (Michael Glaesemann <grzm@seespotcode.net>)
List pgsql-patches
The masks don't need changing.

Your patch has been added to the PostgreSQL unapplied patches list at:

    http://momjian.postgresql.org/cgi-bin/pgpatches

It will be applied as soon as one of the PostgreSQL committers reviews
and approves it.

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


Michael Glaesemann wrote:
> When trying to improve the rounding in interval_div and interval_mul,
> I came across some behavior that seems counterintuitive to me:
>
> test=# select '1.5 mon'::interval;
>      interval
> -----------------
> 1 mon 360:00:00
> (1 row)
>
> With the time/day/month interval struct introduced in 8.1, I'd expect
> this to return '1 mon 15 days'. The reason is that the DecodeInterval
> converts fractional months to time directly, rather than cascading
> first to days.
>
>   Similar behavior happens with weeks:
>
> select '1.5 week'::interval;
>      interval
> -----------------
> 7 days 84:00:00
> (1 row)
>
> Similarly, I believe should return 10 days 12 hours (7 days + 3.5 days).
>
> I've patched DecodeInterval and the regression tests to check this. I
> think tmask lines need to be updated, but I'm not sure how these work
> so I've left them as is. I'd appreciate it if someone could look at
> these areas in particular.
>
> I think this is a behavior changing bug fix, as it was the intention
> of the Interval struct change to treat days and time differently.
> This patch brings the DecodeInterval function more in line with that
> intention.
>
> Thanks for your consideration.
>
> Michael Glaesemann
> grzm seespotcode net
>
>
> Index: src/backend/utils/adt/datetime.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/datetime.c,v
> retrieving revision 1.169
> diff -c -r1.169 datetime.c
> *** src/backend/utils/adt/datetime.c    25 Jul 2006 03:51:21 -0000    1.169
> --- src/backend/utils/adt/datetime.c    27 Aug 2006 23:25:53 -0000
> ***************
> *** 2920,2935 ****
>                            tm->tm_mday += val * 7;
>                            if (fval != 0)
>                            {
> !                             int            sec;
> !
> !                             fval *= 7 * SECS_PER_DAY;
> !                             sec = fval;
> !                             tm->tm_sec += sec;
>    #ifdef HAVE_INT64_TIMESTAMP
> !                             *fsec += (fval - sec) * 1000000;
>    #else
> !                             *fsec += fval - sec;
>    #endif
>                            }
>                            tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
>                            break;
> --- 2920,2942 ----
>                            tm->tm_mday += val * 7;
>                            if (fval != 0)
>                            {
> !                             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;
>    #else
> !                                 *fsec += fval - sec;
>    #endif
> +                             }
>                            }
>                            tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
>                            break;
> ***************
> *** 2938,2953 ****
>                            tm->tm_mon += val;
>                            if (fval != 0)
>                            {
> !                             int            sec;
> !
> !                             fval *= DAYS_PER_MONTH * SECS_PER_DAY;
> !                             sec = fval;
> !                             tm->tm_sec += sec;
>    #ifdef HAVE_INT64_TIMESTAMP
> !                             *fsec += (fval - sec) * 1000000;
>    #else
> !                             *fsec += fval - sec;
>    #endif
>                            }
>                            tmask = DTK_M(MONTH);
>                            break;
> --- 2945,2967 ----
>                            tm->tm_mon += val;
>                            if (fval != 0)
>                            {
> !                             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;
>    #else
> !                                 *fsec += fval - sec;
>    #endif
> +                             }
>                            }
>                            tmask = DTK_M(MONTH);
>                            break;
> Index: src/test/regress/expected/interval.out
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/
> interval.out,v
> retrieving revision 1.15
> diff -c -r1.15 interval.out
> *** src/test/regress/expected/interval.out    6 Mar 2006 22:49:17 -0000
> 1.15
> --- src/test/regress/expected/interval.out    27 Aug 2006 23:25:56 -0000
> ***************
> *** 39,44 ****
> --- 39,56 ----
>     -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: src/test/regress/sql/interval.sql
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/interval.sql,v
> retrieving revision 1.9
> diff -c -r1.9 interval.sql
> *** src/test/regress/sql/interval.sql    6 Mar 2006 22:49:17 -0000    1.9
> --- src/test/regress/sql/interval.sql    27 Aug 2006 23:25:56 -0000
> ***************
> *** 11,16 ****
> --- 11,18 ----
>    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);
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: Have you checked our extensive FAQ?
>
>                http://www.postgresql.org/docs/faq

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Interval aggregate regression failure
Next
From: Michael Glaesemann
Date:
Subject: Re: [HACKERS] Interval aggregate regression failure (expected seems