diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index f4dfec56659..405cea6b6a6 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -3885,8 +3885,18 @@ numeric_log(PG_FUNCTION_ARGS) PG_RETURN_NUMERIC(make_result(&const_zero)); } Assert(NUMERIC_IS_PINF(num2)); - /* log(finite-positive, Inf) is Inf */ - PG_RETURN_NUMERIC(make_result(&const_pinf)); + + /* + * For a finite-positive base, log(base, Inf) = Inf / ln(base), so the + * sign depends on whether base is more or less than 1. If base = 1, + * fall through and let log_var report the error. + */ + init_var_from_num(num1, &arg1); + sign1 = cmp_var(&arg1, &const_one); + if (sign1 < 0) + PG_RETURN_NUMERIC(make_result(&const_ninf)); + if (sign1 > 0) + PG_RETURN_NUMERIC(make_result(&const_pinf)); } /* @@ -10812,6 +10822,16 @@ log_var(const NumericVar *base, const NumericVar *num, NumericVar *result) int ln_base_rscale; int ln_num_rscale; + /* + * ln_var will throw a suitable error for most invalid-input cases, but we + * need a special case for base == 1, else we'd report "division by zero" + * which is a bit confusing. + */ + if (cmp_var(base, &const_one) == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG), + errmsg("cannot take logarithm using base one"))); + init_var(&ln_base); init_var(&ln_num); diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index c58e232a263..fca2cb46c8c 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -933,6 +933,14 @@ FROM v AS v1(x1), v AS v2(x2); NaN | NaN | NaN (16 rows) +SELECT log('0.5'::numeric, 'inf'); + log +----------- + -Infinity +(1 row) + +SELECT log('1'::numeric, 'inf'); +ERROR: cannot take logarithm using base one SELECT log('0'::numeric, '10'); ERROR: cannot take logarithm of zero SELECT log('10'::numeric, '0'); @@ -3492,7 +3500,7 @@ ERROR: cannot take logarithm of zero select log(12.34, 0.0); ERROR: cannot take logarithm of zero select log(1.0, 12.34); -ERROR: division by zero +ERROR: cannot take logarithm using base one -- some random tests select log(1.23e-89, 6.4689e45); log diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index 640c6d92f4c..5fd5c02f636 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -713,6 +713,8 @@ SELECT x1, x2, log(x1, x2) FROM v AS v1(x1), v AS v2(x2); +SELECT log('0.5'::numeric, 'inf'); +SELECT log('1'::numeric, 'inf'); SELECT log('0'::numeric, '10'); SELECT log('10'::numeric, '0'); SELECT log('-inf'::numeric, '10');