From 3481bb0440057043964a3db53acca83649cefc87 Mon Sep 17 00:00:00 2001 From: Abhishek Agarwal <1477457+abhishekagarwal87@users.noreply.github.com> Date: Thu, 8 Jul 2021 16:55:17 +0530 Subject: [PATCH] Better error message for unsupported double values (#11409) A constant expression may evaluate to Double.NEGATIVE_INFINITY/Double.POSITIVE_INFINITY/Double.NAN e.g. log10(0). When using such an expression in native queries, the user will get the corresponding value without any error. In SQL, however, the user will run into NumberFormatException because we convert the double to big-decimal while constructing a literal numeric expression. This probably should be fixed in calcite - see https://issues.apache.org/jira/browse/CALCITE-2067. This PR adds a verbose error message so that users can take corrective action without scratching their heads. --- .../sql/calcite/planner/DruidRexExecutor.java | 9 ++++++++ .../druid/sql/calcite/CalciteQueryTest.java | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidRexExecutor.java b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidRexExecutor.java index c181cb8c885..0f1988a9b24 100644 --- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidRexExecutor.java +++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidRexExecutor.java @@ -126,6 +126,15 @@ public class DruidRexExecutor implements RexExecutor // if exprResult evaluates to Nan or infinity, this will throw a NumberFormatException. // If you find yourself in such a position, consider casting the literal to a BIGINT so that // the query can execute. + double exprResultDouble = exprResult.asDouble(); + if (Double.isNaN(exprResultDouble) || Double.isInfinite(exprResultDouble)) { + String expression = druidExpression.getExpression(); + throw new IAE("'%s' evaluates to '%s' that is not supported in SQL. You can either cast the expression as bigint ('cast(%s as bigint)') or char ('cast(%s as char)') or change the expression itself", + expression, + Double.toString(exprResultDouble), + expression, + expression); + } bigDecimal = BigDecimal.valueOf(exprResult.asDouble()); } literal = rexBuilder.makeLiteral(bigDecimal, constExp.getType(), true); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java index 2c4c87e3fd9..7796018b6a9 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java @@ -283,6 +283,28 @@ public class CalciteQueryTest extends BaseCalciteQueryTest ); } + @Test + public void testSelectConstantExpressionEquivalentToNaN() throws Exception + { + expectedException.expectMessage("'(log10(0) - log10(0))' evaluates to 'NaN' that is not supported in SQL. You can either cast the expression as bigint ('cast((log10(0) - log10(0)) as bigint)') or char ('cast((log10(0) - log10(0)) as char)') or change the expression itself"); + testQuery( + "SELECT log10(0) - log10(0), dim1 FROM foo LIMIT 1", + ImmutableList.of(), + ImmutableList.of() + ); + } + + @Test + public void testSelectConstantExpressionEquivalentToInfinity() throws Exception + { + expectedException.expectMessage("'log10(0)' evaluates to '-Infinity' that is not supported in SQL. You can either cast the expression as bigint ('cast(log10(0) as bigint)') or char ('cast(log10(0) as char)') or change the expression itself"); + testQuery( + "SELECT log10(0), dim1 FROM foo LIMIT 1", + ImmutableList.of(), + ImmutableList.of() + ); + } + @Test public void testGroupByWithPostAggregatorReferencingTimeFloorColumnOnTimeseries() throws Exception {