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

From Bruce Momjian
Subject Re: [BUGS] BUG #2846: inconsistent and confusing
Date
Msg-id 200612282033.kBSKXrt01855@momjian.us
Whole thread Raw
In response to Re: [BUGS] BUG #2846: inconsistent and confusing handling of  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [BUGS] BUG #2846: inconsistent and confusing  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
Tom Lane wrote:
> No, because you are still comparing against FLOAT4_MAX.  I'm suggesting
> that only an actual infinity should be rejected.  Even that is contrary
> to IEEE spec, though.
>
> The other problem with this coding technique is that it must invoke
> isinf three times when the typical case really only requires one (if the
> output isn't inf there is no need to perform isinf on the inputs).
> If we're going to check for overflow at all, I think we should lose the
> subroutine and just do
>
>     if (isinf(result) &&
>         !(isinf(arg1) || isinf(arg2)))
>         ereport(...OVERFLOW...);

I wasn't excited about doing one isinf() call to avoid three, so I just
made a fast isinf() macro:

  /*    We call isinf() a lot, so we use a fast version in this file */
  #define fast_isinf(val)       (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val))

and used that instead of the direct isinf() call.  (We do call fabs() in
the Check* routines.  Should we be using our own Abs()?)  The new patch
also uses float8 for float4 computations, and adds a comment about why
(avoid underflow in some cases).

In looking at the idea of checking for zero as an underflow, I found
most transcendental functions already had such a check, so I moved the check
into the Check*() routines, and added checks for multiplication/division
underflow to zero.  The only outstanding uncaught underflow is from
addition/subtraction.

--
  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    28 Dec 2006 20:32:32 -0000
***************
*** 87,92 ****
--- 87,95 ----
  #define NAN (*(const double *) nan)
  #endif

+ /*    We call isinf() a lot, so we use a fast version in this file */
+ #define fast_isinf(val)    (((val) < DBL_MIN || (val) > DBL_MAX) && isinf(val))
+
  /* not sure what the following should be, but better to make it over-sufficient */
  #define MAXFLOATWIDTH    64
  #define MAXDOUBLEWIDTH    128
***************
*** 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);

--- 107,114 ----
  int            extra_float_digits = 0;        /* Added to DBL_DIG or FLT_DIG */


! static void CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid);
! static void CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid);
  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")));
--- 214,223 ----
   * raise an ereport() error if it is
   */
  static void
! CheckFloat4Val(double val, bool has_inf_args, bool zero_is_valid)
  {
!     /* If one of the input arguments was infinity, allow an infinite result */
!     if (fabs(val) > FLOAT4_MAX && (!fast_isinf(val) || !has_inf_args))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("type \"real\" value out of range: overflow")));
***************
*** 230,242 ****
   * 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")));
!     if (val != 0.0 && fabs(val) < FLOAT8_MIN)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
           errmsg("type \"double precision\" value out of range: underflow")));
--- 234,263 ----
   * raise an ereport() error if it is
   */
  static void
! CheckFloat8Val(double val, bool has_inf_args, bool zero_is_valid)
  {
!     /*
!      *    Computations that slightly exceed FLOAT8_MAX are non-Infinity,
!      *    but those that greatly exceed FLOAT8_MAX become Infinity.  Therefore
!      *    it is difficult to tell if a value is really infinity or the result
!      *    of an overflow.  The solution is to use a boolean indicating if
!      *    the input arguments were infiity, meaning an infinite result is
!      *    probably not the result of an overflow.  This allows various
!      *    computations like SELECT 'Inf'::float8 + 5.
!      */
!     if (fabs(val) > FLOAT8_MAX && (!fast_isinf(val) || !has_inf_args))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
            errmsg("type \"double precision\" value out of range: overflow")));
!     /*
!      *    Underflow has similar issues to overflow, i.e. if a computation is
!      *    slighly smaller than FLOAT8_MIN, the result is non-zero, but if it is
!      *    much smaller than FLOAT8_MIN, the value becomes zero.  However,
!      *    unlike overflow, zero is not a special value and can be the result
!      *    of a computation, so we pass in a boolean indicating if zero is
!      *    a valid result.
!      */
!     if ((val != 0.0 && fabs(val) < FLOAT8_MIN) || (val == 0 && !zero_is_valid))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
           errmsg("type \"double precision\" value out of range: underflow")));
***************
*** 334,340 ****
       * input is "infinity" we have to skip over "inity".  Also, it may
       * return positive infinity for "-inf".
       */
!     if (isinf(val))
      {
          if (pg_strncasecmp(num, "Infinity", 8) == 0)
          {
--- 355,361 ----
       * input is "infinity" we have to skip over "inity".  Also, it may
       * return positive infinity for "-inf".
       */
!     if (fast_isinf(val))
      {
          if (pg_strncasecmp(num, "Infinity", 8) == 0)
          {
***************
*** 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);
  }
--- 390,396 ----
       * if we get here, we have a legal double, still need to check to see if
       * it's a legal float4
       */
!     CheckFloat4Val(val, true, true);

      PG_RETURN_FLOAT4((float4) val);
  }
***************
*** 527,533 ****
       * input is "infinity" we have to skip over "inity".  Also, it may
       * return positive infinity for "-inf".
       */
!     if (isinf(val))
      {
          if (pg_strncasecmp(num, "Infinity", 8) == 0)
          {
--- 547,553 ----
       * input is "infinity" we have to skip over "inity".  Also, it may
       * return positive infinity for "-inf".
       */
!     if (fast_isinf(val))
      {
          if (pg_strncasecmp(num, "Infinity", 8) == 0)
          {
***************
*** 558,565 ****
               errmsg("invalid input syntax for type double precision: \"%s\"",
                      orig_num)));

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

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

!     CheckFloat8Val(val, true, true);

      PG_RETURN_FLOAT8(val);
  }
***************
*** 652,659 ****
  float4um(PG_FUNCTION_ARGS)
  {
      float4        arg1 = PG_GETARG_FLOAT4(0);

!     PG_RETURN_FLOAT4((float4) -arg1);
  }

  Datum
--- 671,682 ----
  float4um(PG_FUNCTION_ARGS)
  {
      float4        arg1 = PG_GETARG_FLOAT4(0);
+     float4        result;
+
+     result = ((arg1 != 0) ? -(arg1) : arg1);

!     CheckFloat4Val(result, fast_isinf(arg1), true);
!     PG_RETURN_FLOAT4(result);
  }

  Datum
***************
*** 705,716 ****
  float8abs(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
-     float8        result;

!     result = fabs(arg1);
!
!     CheckFloat8Val(result);
!     PG_RETURN_FLOAT8(result);
  }


--- 728,735 ----
  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);
  }

--- 744,750 ----

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

!     CheckFloat8Val(result, fast_isinf(arg1), true);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 781,824 ****
  Datum
  float4pl(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4mi(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4mul(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4div(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

      if (arg2 == 0.0)
--- 800,849 ----
  Datum
  float4pl(PG_FUNCTION_ARGS)
  {
!     /*
!      *    Use float8 so that we have a larger underflow range.
!      *    Some compilers do not promote float to double in
!      *    computations.
!      */
!     float8        arg1 = PG_GETARG_FLOAT4(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4mi(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4mul(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

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

  Datum
  float4div(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      double        result;

      if (arg2 == 0.0)
***************
*** 827,835 ****
                   errmsg("division by zero")));

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

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

--- 852,860 ----
                   errmsg("division by zero")));

      /* Do division in float8, then check for overflow */
!     result = arg1 / arg2;

!     CheckFloat4Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
      PG_RETURN_FLOAT4((float4) result);
  }

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

      result = arg1 + arg2;

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

--- 873,879 ----

      result = arg1 + arg2;

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

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

      result = arg1 - arg2;

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

--- 886,892 ----

      result = arg1 - arg2;

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

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

      result = arg1 * arg2;

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

--- 899,906 ----

      result = arg1 * arg2;

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2),
!                     arg1 == 0 || arg2 == 0);
      PG_RETURN_FLOAT8(result);
  }

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

      result = arg1 / arg2;

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

--- 918,924 ----

      result = arg1 / arg2;

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

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

!     CheckFloat4Val(num);

      PG_RETURN_FLOAT4((float4) num);
  }
--- 1168,1174 ----
  {
      float8        num = PG_GETARG_FLOAT8(0);

!     CheckFloat4Val(num, fast_isinf(num), true);

      PG_RETURN_FLOAT4((float4) num);
  }
***************
*** 1157,1163 ****
      float8        num = PG_GETARG_FLOAT8(0);
      int32        result;

!     if (num < INT_MIN || num > INT_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("integer out of range")));
--- 1183,1190 ----
      float8        num = PG_GETARG_FLOAT8(0);
      int32        result;

!     /* 'Inf' is handled by INT_MAX */
!     if (num < INT_MIN || num > INT_MAX || isnan(num))
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("integer out of range")));
***************
*** 1176,1182 ****
      float8        num = PG_GETARG_FLOAT8(0);
      int16        result;

!     if (num < SHRT_MIN || num > SHRT_MAX)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("smallint out of range")));
--- 1203,1209 ----
      float8        num = PG_GETARG_FLOAT8(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")));
***************
*** 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")));
--- 1250,1256 ----
      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")));
--- 1269,1275 ----
      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);
  }

--- 1512,1518 ----

      result = sqrt(arg1);

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1500,1505 ****
--- 1527,1533 ----
      float8        result;

      result = cbrt(arg1);
+     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      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);
  }

--- 1567,1573 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1555,1575 ****

      /*
       * We must check both for errno getting set and for a NaN result, in order
!      * to deal with the vagaries of different platforms. Also, a zero result
!      * implies unreported underflow.
       */
      errno = 0;
      result = exp(arg1);
!     if (errno != 0 || result == 0.0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

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

--- 1583,1598 ----

      /*
       * We must check both for errno getting set and for a NaN result, in order
!      * to deal with the vagaries of different platforms.
       */
      errno = 0;
      result = exp(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("result is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), false);
      PG_RETURN_FLOAT8(result);
  }

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

      result = log(arg1);

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

--- 1621,1627 ----

      result = log(arg1);

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1);
      PG_RETURN_FLOAT8(result);
  }

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

      result = log10(arg1);

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

--- 1651,1657 ----

      result = log10(arg1);

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 1);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1644,1659 ****

      errno = 0;
      result = acos(arg1);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1667,1678 ----

      errno = 0;
      result = acos(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), true);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1669,1684 ****

      errno = 0;
      result = asin(arg1);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1688,1699 ----

      errno = 0;
      result = asin(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), true);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1694,1709 ****

      errno = 0;
      result = atan(arg1);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1709,1720 ----

      errno = 0;
      result = atan(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1720,1735 ****

      errno = 0;
      result = atan2(arg1, arg2);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1731,1742 ----

      errno = 0;
      result = atan2(arg1, arg2);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg2 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1745,1760 ****

      errno = 0;
      result = cos(arg1);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1752,1763 ----

      errno = 0;
      result = cos(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), true);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1770,1786 ****

      errno = 0;
      result = tan(arg1);
!     if (errno != 0 || result == 0.0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1773,1785 ----

      errno = 0;
      result = tan(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

***************
*** 1796,1811 ****

      errno = 0;
      result = sin(arg1);
!     if (errno != 0
! #ifdef HAVE_FINITE
!         || !finite(result)
! #endif
!         )
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

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

--- 1795,1806 ----

      errno = 0;
      result = sin(arg1);
!     if (errno != 0)
          ereport(ERROR,
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), true);
      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);
  }

--- 1825,1831 ----
                  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                   errmsg("input is out of range")));

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

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

      result = arg1 * (180.0 / M_PI);

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

--- 1841,1847 ----

      result = arg1 * (180.0 / M_PI);

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

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

      result = arg1 * (M_PI / 180.0);

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

--- 1867,1873 ----

      result = arg1 * (M_PI / 180.0);

!     CheckFloat8Val(result, fast_isinf(arg1), arg1 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 1963,1970 ****

      N += 1.0;
      sumX += newval;
      sumX2 += newval * newval;
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 1958,1967 ----

      N += 1.0;
      sumX += newval;
+     CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true);
      sumX2 += newval * newval;
!     CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true);
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 1999,2023 ****
  float4_accum(PG_FUNCTION_ARGS)
  {
      ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
!     float4        newval4 = PG_GETARG_FLOAT4(1);
      float8       *transvalues;
      float8        N,
                  sumX,
!                 sumX2,
!                 newval;

      transvalues = check_float8_array(transarray, "float4_accum", 3);
      N = transvalues[0];
      sumX = transvalues[1];
      sumX2 = transvalues[2];

-     /* Do arithmetic in float8 for best accuracy */
-     newval = newval4;
-
      N += 1.0;
      sumX += newval;
      sumX2 += newval * newval;
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 1996,2023 ----
  float4_accum(PG_FUNCTION_ARGS)
  {
      ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
!     /*
!      *    Use float8 so that we have a larger underflow range.
!      *    Some compilers do not promote float to double in
!      *    computations.
!      */
!     float8        newval = PG_GETARG_FLOAT4(1);
      float8       *transvalues;
      float8        N,
                  sumX,
!                 sumX2;

      transvalues = check_float8_array(transarray, "float4_accum", 3);
      N = transvalues[0];
      sumX = transvalues[1];
      sumX2 = transvalues[2];

      N += 1.0;
      sumX += newval;
+     CheckFloat4Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newval), true);
      sumX2 += newval * newval;
!     CheckFloat4Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newval), true);
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 2088,2093 ****
--- 2088,2094 ----
          PG_RETURN_NULL();

      numerator = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2116,2121 ****
--- 2117,2123 ----
          PG_RETURN_NULL();

      numerator = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2144,2149 ****
--- 2146,2152 ----
          PG_RETURN_NULL();

      numerator = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2172,2177 ****
--- 2175,2181 ----
          PG_RETURN_NULL();

      numerator = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2220,2230 ****

      N += 1.0;
      sumX += newvalX;
      sumX2 += newvalX * newvalX;
      sumY += newvalY;
      sumY2 += newvalY * newvalY;
      sumXY += newvalX * newvalY;
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
--- 2224,2240 ----

      N += 1.0;
      sumX += newvalX;
+     CheckFloat8Val(sumX, fast_isinf(transvalues[1]) || fast_isinf(newvalX), true);
      sumX2 += newvalX * newvalX;
+     CheckFloat8Val(sumX2, fast_isinf(transvalues[2]) || fast_isinf(newvalX), true);
      sumY += newvalY;
+     CheckFloat8Val(sumY, fast_isinf(transvalues[3]) || fast_isinf(newvalY), true);
      sumY2 += newvalY * newvalY;
+     CheckFloat8Val(sumY2, fast_isinf(transvalues[4]) || fast_isinf(newvalY), true);
      sumXY += newvalX * newvalY;
!     CheckFloat8Val(sumXY, fast_isinf(transvalues[5]) || fast_isinf(newvalX) ||
!                     fast_isinf(newvalY), true);
!
      /*
       * If we're invoked by nodeAgg, we can cheat and modify our first
       * parameter in-place to reduce palloc overhead. Otherwise we construct a
***************
*** 2282,2287 ****
--- 2292,2298 ----
          PG_RETURN_NULL();

      numerator = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numerator, fast_isinf(sumX2) || fast_isinf(sumX), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2310,2315 ****
--- 2321,2327 ----
          PG_RETURN_NULL();

      numerator = N * sumY2 - sumY * sumY;
+     CheckFloat8Val(numerator, fast_isinf(sumY2) || fast_isinf(sumY), true);

      /* Watch out for roundoff error producing a negative numerator */
      if (numerator <= 0.0)
***************
*** 2340,2345 ****
--- 2352,2359 ----
          PG_RETURN_NULL();

      numerator = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);

      /* A negative result is valid here */

***************
*** 2406,2411 ****
--- 2420,2427 ----
          PG_RETURN_NULL();

      numerator = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);

      PG_RETURN_FLOAT8(numerator / (N * N));
  }
***************
*** 2432,2437 ****
--- 2448,2455 ----
          PG_RETURN_NULL();

      numerator = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numerator, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);

      PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
  }
***************
*** 2464,2471 ****
--- 2482,2493 ----
          PG_RETURN_NULL();

      numeratorX = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
      numeratorY = N * sumY2 - sumY * sumY;
+     CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true);
      numeratorXY = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);
      if (numeratorX <= 0 || numeratorY <= 0)
          PG_RETURN_NULL();

***************
*** 2501,2508 ****
--- 2523,2534 ----
          PG_RETURN_NULL();

      numeratorX = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
      numeratorY = N * sumY2 - sumY * sumY;
+     CheckFloat8Val(numeratorY, fast_isinf(sumY2) || fast_isinf(sumY), true);
      numeratorXY = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);
      if (numeratorX <= 0)
          PG_RETURN_NULL();
      /* per spec, horizontal line produces 1.0 */
***************
*** 2538,2544 ****
--- 2564,2573 ----
          PG_RETURN_NULL();

      numeratorX = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
      numeratorXY = N * sumXY - sumX * sumY;
+     CheckFloat8Val(numeratorXY, fast_isinf(sumXY) || fast_isinf(sumX) ||
+                     fast_isinf(sumY), true);
      if (numeratorX <= 0)
          PG_RETURN_NULL();

***************
*** 2570,2576 ****
--- 2599,2608 ----
          PG_RETURN_NULL();

      numeratorX = N * sumX2 - sumX * sumX;
+     CheckFloat8Val(numeratorX, fast_isinf(sumX2) || fast_isinf(sumX), true);
      numeratorXXY = sumY * sumX2 - sumX * sumXY;
+     CheckFloat8Val(numeratorXXY, fast_isinf(sumY) || fast_isinf(sumX2) ||
+                     fast_isinf(sumX) || fast_isinf(sumXY), true);
      if (numeratorX <= 0)
          PG_RETURN_NULL();

***************
*** 2593,2635 ****
  Datum
  float48pl(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48mi(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48mul(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48div(PG_FUNCTION_ARGS)
  {
!     float4        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

--- 2625,2673 ----
  Datum
  float48pl(PG_FUNCTION_ARGS)
  {
!     /*
!      *    Use float8 so that we have a larger underflow range.
!      *    Some compilers do not promote float to double in
!      *    computations.
!      */
!     float8        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48mi(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48mul(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

  Datum
  float48div(PG_FUNCTION_ARGS)
  {
!     float8        arg1 = PG_GETARG_FLOAT4(0);
      float8        arg2 = PG_GETARG_FLOAT8(1);
      float8        result;

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

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

--- 2677,2683 ----
                   errmsg("division by zero")));

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

***************
*** 2653,2664 ****
  float84pl(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 + arg2;

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

--- 2691,2702 ----
  float84pl(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 + arg2;

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

***************
*** 2666,2677 ****
  float84mi(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 - arg2;

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

--- 2704,2715 ----
  float84mi(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 - arg2;

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

***************
*** 2679,2690 ****
  float84mul(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 * arg2;

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

--- 2717,2729 ----
  float84mul(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      result = arg1 * arg2;

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2),
!                     arg1 == 0 || arg2 == 0);
      PG_RETURN_FLOAT8(result);
  }

***************
*** 2692,2698 ****
  float84div(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float4        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      if (arg2 == 0.0)
--- 2731,2737 ----
  float84div(PG_FUNCTION_ARGS)
  {
      float8        arg1 = PG_GETARG_FLOAT8(0);
!     float8        arg2 = PG_GETARG_FLOAT4(1);
      float8        result;

      if (arg2 == 0.0)
***************
*** 2702,2708 ****

      result = arg1 / arg2;

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

--- 2741,2747 ----

      result = arg1 / arg2;

!     CheckFloat8Val(result, fast_isinf(arg1) || fast_isinf(arg2), arg1 == 0);
      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    28 Dec 2006 20:32:33 -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);
Index: src/test/regress/expected/float4.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/float4.out,v
retrieving revision 1.13
diff -c -c -r1.13 float4.out
*** src/test/regress/expected/float4.out    7 Apr 2005 01:51:40 -0000    1.13
--- src/test/regress/expected/float4.out    28 Dec 2006 20:32:35 -0000
***************
*** 72,78 ****
  SELECT ' INFINITY    x'::float4;
  ERROR:  invalid input syntax for type real: " INFINITY    x"
  SELECT 'Infinity'::float4 + 100.0;
! ERROR:  type "double precision" value out of range: overflow
  SELECT 'Infinity'::float4 / 'Infinity'::float4;
   ?column?
  ----------
--- 72,82 ----
  SELECT ' INFINITY    x'::float4;
  ERROR:  invalid input syntax for type real: " INFINITY    x"
  SELECT 'Infinity'::float4 + 100.0;
!  ?column?
! ----------
!  Infinity
! (1 row)
!
  SELECT 'Infinity'::float4 / 'Infinity'::float4;
   ?column?
  ----------
Index: src/test/regress/expected/float8.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/float8.out,v
retrieving revision 1.24
diff -c -c -r1.24 float8.out
*** src/test/regress/expected/float8.out    8 Jun 2005 21:15:29 -0000    1.24
--- src/test/regress/expected/float8.out    28 Dec 2006 20:32:35 -0000
***************
*** 72,78 ****
  SELECT ' INFINITY    x'::float8;
  ERROR:  invalid input syntax for type double precision: " INFINITY    x"
  SELECT 'Infinity'::float8 + 100.0;
! ERROR:  type "double precision" value out of range: overflow
  SELECT 'Infinity'::float8 / 'Infinity'::float8;
   ?column?
  ----------
--- 72,82 ----
  SELECT ' INFINITY    x'::float8;
  ERROR:  invalid input syntax for type double precision: " INFINITY    x"
  SELECT 'Infinity'::float8 + 100.0;
!  ?column?
! ----------
!  Infinity
! (1 row)
!
  SELECT 'Infinity'::float8 / 'Infinity'::float8;
   ?column?
  ----------
***************
*** 350,356 ****
  SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
  ERROR:  cannot take logarithm of a negative number
  SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
! ERROR:  result is out of range
  SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
  ERROR:  division by zero
  SELECT '' AS five, * FROM FLOAT8_TBL;
--- 354,360 ----
  SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
  ERROR:  cannot take logarithm of a negative number
  SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
! ERROR:  type "double precision" value out of range: underflow
  SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
  ERROR:  division by zero
  SELECT '' AS five, * FROM FLOAT8_TBL;

pgsql-patches by date:

Previous
From: "Simon Riggs"
Date:
Subject: Re: Dead Space Map patch
Next
From: Euler Taveira de Oliveira
Date:
Subject: Re: xlog directory at initdb time