Re: [BUGS] BUG #2846: inconsistent and confusing handling of - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [BUGS] BUG #2846: inconsistent and confusing handling of
Date
Msg-id 200612240650.kBO6oFh09463@momjian.us
Whole thread Raw
List pgsql-patches
Roman Kononov wrote:
>
> The following bug has been logged online:
>
> Bug reference:      2846
> Logged by:          Roman Kononov
> Email address:      kononov195-pgsql@yahoo.com
> PostgreSQL version: 8.2.0 and older
> Operating system:   linux 2.6.15-27-amd64 ubuntu
> Description:        inconsistent and confusing handling of underflows, NaNs
> and INFs
> Details:

This is a very interesting bug report.  It seems you have done some good
analysis of PostgreSQL and how it handles certain corner cases,
infinity, and NaN.

I have researched your findings and will show some fixes below:

> Please compare the results of the simple queries.
> ==============================================
> test=# select ('NaN'::float4)::int2;
>  int2
> ------
>     0
> (1 row)

There certainly should be an isnan() test when converting to int2
because while float can represent NaN, int2 cannot.  The fix shows:

    test=> select ('NaN'::float4)::int2;
    ERROR:  smallint out of range

> test=# select ('NaN'::float4)::int4;
>     int4
> -------------
>  -2147483648
> (1 row)

Same for int4:

    test=> select ('NaN'::float4)::int4;
    ERROR:  integer out of range

> test=# select ('NaN'::float4)::int8;
> ERROR:  bigint out of range

This one was correct because it uses rint() internally.

> test=# select ('nan'::numeric)::int4;
> ERROR:  cannot convert NaN to integer
> ==============================================
> test=# select abs('INF'::float4);
>    abs
> ----------
>  Infinity
> (1 row)

Correct.

> test=# select abs('INF'::float8);
> ERROR:  type "double precision" value out of range: overflow

This one was more complicated.  float4/8 operations test for
results > FLOAT[84]_MAX.  This is because if you do this:

    test=> select (1e201::float8)*(1e200::float8);

the result internally is Infinity, so they check for Inf as a check for
overflow.  The bottom line is that while the current code allows
infinity to be entered, it does not allow the value to operate in many
context because it is assumes Inf to be an overflow indicator.  I have
fixed this by passing a boolean to indicate if any of the operands were
infinity, and if so, allow an infinite result, so this now works:

    test=> select abs('INF'::float8);
       abs
    ----------
     Infinity
    (1 row)

> ==============================================
> test=# select -('INF'::float4);
>  ?column?
> -----------
>  -Infinity
> (1 row)
>
> test=# select -('INF'::float8);
> ERROR:  type "double precision" value out of range: overflow

And this now works too:

    test=> select -('INF'::float8);
     ?column?
    -----------
     -Infinity
    (1 row)

> ==============================================
> test=# select (1e-37::float4)*(1e-22::float4);
>  ?column?
> ----------
>         0
> (1 row)

This one is quite complex.  For overflow, there is a range of values
that is represented as > FLOAT8_MAX, but for values very large, the
result becomes Inf.  The old code assumed an Inf result was an overflow,
and threw an error, as I outlined above.  The new code does a better
job.

Now, for underflow.  For underflow, we again have a range slightly
smaller than DBL_MIN where we can detect an underflow, and throw an
error, but just like overflow, if the underflow is too small, the result
becomes zero.  The bad news is that unlike Inf, zero isn't a special
value.  With Inf, we could say if we got an infinite result from
non-infinite arguments, we had an overflow, but for underflow, how do we
know if zero is an underflow or just the correct result?  For
multiplication, we could say that a zero result for non-zero arguments
is almost certainly an underflow, but I don't see how we can handle the
other operations as simply.

I was not able to fix the underflow problems you reported.

> test=# select (1e-37::float4)*(1e-2::float4);
> ERROR:  type "real" value out of range: underflow
> ==============================================
> test=# select (1e-300::float8)*(1e-30::float8);
>  ?column?
> ----------
>         0
> (1 row)
>
> test=# select (1e-300::float8)*(1e-20::float8);
> ERROR:  type "double precision" value out of range: underflow
> ==============================================
> test=# select ('INF'::float8-'INF'::float8);
>  ?column?
> ----------
>       NaN
> (1 row)
>
> test=# select ('INF'::float8+'INF'::float8);
> ERROR:  type "double precision" value out of range: overflow

This works fine now:

    test=> select ('INF'::float8+'INF'::float8);
     ?column?
    ----------
     Infinity
    (1 row)

> ==============================================
> test=# select ('INF'::float4)::float8;
>   float8
> ----------
>  Infinity
> (1 row)
>
> test=# select ('INF'::float8)::float4;
> ERROR:  type "real" value out of range: overflow
> ==============================================
> test=# select cbrt('INF'::float4);
>    cbrt
> ----------
>  Infinity
> (1 row)
>
> test=# select sqrt('INF'::float4);
> ERROR:  type "double precision" value out of range: overflow

This works fine too:

    test=> select ('INF'::float8)::float4;
      float4
    ----------
     Infinity
    (1 row)

> ==============================================
> test=# select ((-32768::int8)::int2)%(-1::int2);
>  ?column?
> ----------
>         0
> (1 row)
>
> test=# select ((-2147483648::int8)::int4)%(-1::int4);
> ERROR:  floating-point exception
> DETAIL:  An invalid floating-point operation was signaled. This probably
> means an out-of-range result or an invalid operation, such
> as division by zero.

This was an interesting case.  It turns out the value has to be INT_MIN,
and the second value has to be -1.  The exception happens, I think,
because the CPU does the division first before getting the remainder,
and INT_MIN / -1 is > INT_MAX, hence the error.  I just special-cased it
to return zero in the int4mod() code:

    test=> select ((-2147483648::int8)::int4)%(-1::int4);
     ?column?
    ----------
            0
    (1 row)

You can actually show the error without using int8:

    test=> select ((-2147483648)::int4) % (-1);
     ?column?
    ----------
            0
    (1 row)

The parentheses are required to make the value negative before the cast
to int4.

> ==============================================
> test=# create table tt (ff float8);
> CREATE TABLE
> test=# insert into tt values (1e308),(1e308),(1e308);
> INSERT 0 3
> test=# select * from tt;
>    ff
> --------
>  1e+308
>  1e+308
>  1e+308
> (3 rows)
>
> test=# select avg(ff) from tt;
>    avg
> ----------
>  Infinity
> (1 row)
>
> test=# select stddev(ff) from tt;
>  stddev
> --------
>     NaN
> (1 row)

I didn't study the aggregate cases.  Does someone want to look those
over?

The attached patch fixes all the items I mentioned above.

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

  + If your life is a hard drive, Christ can be your backup. +
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/float.c,v
retrieving revision 1.131
diff -c -c -r1.131 float.c
*** src/backend/utils/adt/float.c    23 Dec 2006 02:13:24 -0000    1.131
--- src/backend/utils/adt/float.c    24 Dec 2006 06:48:08 -0000
***************
*** 104,111 ****
  int            extra_float_digits = 0;        /* Added to DBL_DIG or FLT_DIG */


! static void CheckFloat4Val(double val);
! static void CheckFloat8Val(double val);
  static int    float4_cmp_internal(float4 a, float4 b);
  static int    float8_cmp_internal(float8 a, float8 b);

--- 104,111 ----
  int            extra_float_digits = 0;        /* Added to DBL_DIG or FLT_DIG */


! static void CheckFloat4Val(double val, bool isinf_args);
! static void CheckFloat8Val(double val, bool isinf_args);
  static int    float4_cmp_internal(float4 a, float4 b);
  static int    float8_cmp_internal(float8 a, float8 b);

***************
*** 211,219 ****
   * raise an ereport() error if it is
   */
  static void
! CheckFloat4Val(double val)
  {
!     if (fabs(val) > FLOAT4_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("type \"real\" value out of range: overflow")));
--- 211,220 ----
   * raise an ereport() error if it is
   */
  static void
! CheckFloat4Val(double val, bool isinf_args)
  {
!     /* If one of the input arguments was infinity, allow an infinite result */
!     if (fabs(val) > FLOAT4_MAX && (!isinf(val) || !isinf_args))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("type \"real\" value out of range: overflow")));
***************
*** 230,238 ****
   * raise an ereport() error if it is
   */
  static void
! CheckFloat8Val(double val)
  {
!     if (fabs(val) > FLOAT8_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
            errmsg("type \"double precision\" value out of range: overflow")));
--- 231,240 ----
   * raise an ereport() error if it is
   */
  static void
! CheckFloat8Val(double val, bool isinf_args)
  {
!     /* If one of the input arguments was infinity, allow an infinite result */
!     if (fabs(val) > FLOAT8_MAX && (!isinf(val) || !isinf_args))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
            errmsg("type \"double precision\" value out of range: overflow")));
***************
*** 369,376 ****
       * if we get here, we have a legal double, still need to check to see if
       * it's a legal float4
       */
!     if (!isinf(val))
!         CheckFloat4Val(val);

      PG_RETURN_FLOAT4((float4) val);
  }
--- 371,377 ----
       * if we get here, we have a legal double, still need to check to see if
       * it's a legal float4
       */
!     CheckFloat4Val(val, true /* allow Inf */);

      PG_RETURN_FLOAT4((float4) val);
  }
***************
*** 558,565 ****
               errmsg("invalid input syntax for type double precision: \"%s\"",
                      orig_num)));

!     if (!isinf(val))
!         CheckFloat8Val(val);

      PG_RETURN_FLOAT8(val);
  }
--- 559,565 ----
               errmsg("invalid input syntax for type double precision: \"%s\"",
                      orig_num)));

!     CheckFloat8Val(val, true /* allow Inf */);

      PG_RETURN_FLOAT8(val);
  }
***************
*** 705,716 ****
  float8abs(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
-     float8        result;
-
-     result = fabs(arg1);

!     CheckFloat8Val(result);
!     PG_RETURN_FLOAT8(result);
  }


--- 705,712 ----
  float8abs(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);

!     PG_RETURN_FLOAT8(fabs(arg1));
  }


***************
*** 725,731 ****

      result = ((arg1 != 0) ? -(arg1) : arg1);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 721,727 ----

      result = ((arg1 != 0) ? -(arg1) : arg1);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 786,792 ****
      double        result;

      result = arg1 + arg2;
!     CheckFloat4Val(result);
      PG_RETURN_FLOAT4((float4) result);
  }

--- 782,788 ----
      double        result;

      result = arg1 + arg2;
!     CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT4((float4) result);
  }

***************
*** 798,804 ****
      double        result;

      result = arg1 - arg2;
!     CheckFloat4Val(result);
      PG_RETURN_FLOAT4((float4) result);
  }

--- 794,800 ----
      double        result;

      result = arg1 - arg2;
!     CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT4((float4) result);
  }

***************
*** 810,816 ****
      double        result;

      result = arg1 * arg2;
!     CheckFloat4Val(result);
      PG_RETURN_FLOAT4((float4) result);
  }

--- 806,812 ----
      double        result;

      result = arg1 * arg2;
!     CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT4((float4) result);
  }

***************
*** 829,835 ****
      /* Do division in float8, then check for overflow */
      result = (float8) arg1 / (float8) arg2;

!     CheckFloat4Val(result);
      PG_RETURN_FLOAT4((float4) result);
  }

--- 825,831 ----
      /* Do division in float8, then check for overflow */
      result = (float8) arg1 / (float8) arg2;

!     CheckFloat4Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT4((float4) result);
  }

***************
*** 848,854 ****

      result = arg1 + arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 844,850 ----

      result = arg1 + arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 861,867 ****

      result = arg1 - arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 857,863 ----

      result = arg1 - arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 874,880 ****

      result = arg1 * arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 870,876 ----

      result = arg1 * arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 892,898 ****

      result = arg1 / arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 888,894 ----

      result = arg1 / arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1142,1148 ****
  {
      float8        num = PG_GETARG_FLOAT8(0);

!     CheckFloat4Val(num);

      PG_RETURN_FLOAT4((float4) num);
  }
--- 1138,1144 ----
  {
      float8        num = PG_GETARG_FLOAT8(0);

!     CheckFloat4Val(num, isinf(num));

      PG_RETURN_FLOAT4((float4) num);
  }
***************
*** 1223,1229 ****
      float4        num = PG_GETARG_FLOAT4(0);
      int32        result;

!     if (num < INT_MIN || num > INT_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("integer out of range")));
--- 1219,1225 ----
      float4        num = PG_GETARG_FLOAT4(0);
      int32        result;

!     if (num < INT_MIN || num > INT_MAX || isnan(num))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("integer out of range")));
***************
*** 1242,1248 ****
      float4        num = PG_GETARG_FLOAT4(0);
      int16        result;

!     if (num < SHRT_MIN || num > SHRT_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("smallint out of range")));
--- 1238,1244 ----
      float4        num = PG_GETARG_FLOAT4(0);
      int16        result;

!     if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("smallint out of range")));
***************
*** 1485,1491 ****

      result = sqrt(arg1);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1481,1487 ----

      result = sqrt(arg1);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1539,1545 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1535,1541 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1569,1575 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1565,1571 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1598,1604 ****

      result = log(arg1);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1594,1600 ----

      result = log(arg1);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1628,1634 ****

      result = log10(arg1);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1624,1630 ----

      result = log10(arg1);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1653,1659 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1649,1655 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1678,1684 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1674,1680 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1703,1709 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1699,1705 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1729,1735 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1725,1731 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1754,1760 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1750,1756 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1780,1786 ****
                   errmsg("input is out of range")));

      result = 1.0 / result;
!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1776,1782 ----
                   errmsg("input is out of range")));

      result = 1.0 / result;
!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1805,1811 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1801,1807 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1830,1836 ****
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1826,1832 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1846,1852 ****

      result = arg1 * (180.0 / M_PI);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1842,1848 ----

      result = arg1 * (180.0 / M_PI);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1872,1878 ****

      result = arg1 * (M_PI / 180.0);

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 1868,1874 ----

      result = arg1 * (M_PI / 180.0);

!     CheckFloat8Val(result, isinf(arg1));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2598,2604 ****
      float8        result;

      result = arg1 + arg2;
!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2594,2600 ----
      float8        result;

      result = arg1 + arg2;
!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2610,2616 ****
      float8        result;

      result = arg1 - arg2;
!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2606,2612 ----
      float8        result;

      result = arg1 - arg2;
!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2622,2628 ****
      float8        result;

      result = arg1 * arg2;
!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2618,2624 ----
      float8        result;

      result = arg1 * arg2;
!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2639,2645 ****
                   errmsg("division by zero")));

      result = arg1 / arg2;
!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2635,2641 ----
                   errmsg("division by zero")));

      result = arg1 / arg2;
!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2658,2664 ****

      result = arg1 + arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2654,2660 ----

      result = arg1 + arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2671,2677 ****

      result = arg1 - arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2667,2673 ----

      result = arg1 - arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2684,2690 ****

      result = arg1 * arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2680,2686 ----

      result = arg1 * arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2702,2708 ****

      result = arg1 / arg2;

!     CheckFloat8Val(result);
      PG_RETURN_FLOAT8(result);
  }

--- 2698,2704 ----

      result = arg1 / arg2;

!     CheckFloat8Val(result, isinf(arg1) || isinf(arg2));
      PG_RETURN_FLOAT8(result);
  }

Index: src/backend/utils/adt/int.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/int.c,v
retrieving revision 1.75
diff -c -c -r1.75 int.c
*** src/backend/utils/adt/int.c    4 Oct 2006 00:29:59 -0000    1.75
--- src/backend/utils/adt/int.c    24 Dec 2006 06:48:09 -0000
***************
*** 1124,1129 ****
--- 1124,1134 ----
          ereport(ERROR,
                  (errcode(ERRCODE_DIVISION_BY_ZERO),
                   errmsg("division by zero")));
+
+     /* SELECT ((-2147483648)::int4) % (-1); causes a floating point exception */
+     if (arg1 == INT_MIN && arg2 == -1)
+         PG_RETURN_INT32(0);
+
      /* No overflow is possible */

      PG_RETURN_INT32(arg1 % arg2);

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Patch(es) to expose n_live_tuples and
Next
From: "Jaime Casanova"
Date:
Subject: Re: Tablespace for temporary objects and sort files