This is an automated email from the ASF dual-hosted git repository. rubenql pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push: new d08b5cf73f [CALCITE-5691] IN sub-query inside FILTER clause throws IndexOutOfBoundsException d08b5cf73f is described below commit d08b5cf73f9bb438f282d2089dd92f6d380c0c47 Author: Runkang He <hrun...@gmail.com> AuthorDate: Thu May 11 08:59:29 2023 +0800 [CALCITE-5691] IN sub-query inside FILTER clause throws IndexOutOfBoundsException --- .../apache/calcite/plan/RelOptPredicateList.java | 10 +++--- .../apache/calcite/test/SqlToRelConverterTest.java | 13 ++++++++ .../apache/calcite/test/SqlToRelConverterTest.xml | 32 ++++++++++++++++++ core/src/test/resources/sql/sub-query.iq | 38 ++++++++++++++++++++++ 4 files changed, 89 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java index 405ac30b91..d6f1de5ce1 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java @@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableMap; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collection; +import java.util.List; import java.util.Objects; /** @@ -236,10 +237,11 @@ public class RelOptPredicateList { if (SqlKind.COMPARISON.contains(e.getKind())) { // A comparison with a (non-null) literal, such as 'ref < 10', is not null if 'ref' // is not null. - RexCall call = (RexCall) e; - if (call.getOperands().get(1) instanceof RexLiteral - && !((RexLiteral) call.getOperands().get(1)).isNull()) { - return isEffectivelyNotNull(call.getOperands().get(0)); + List<RexNode> operands = ((RexCall) e).getOperands(); + // We can have just one operand in case e.g. of a RexSubQuery with IN operator. + if (operands.size() > 1 && operands.get(1) instanceof RexLiteral + && !((RexLiteral) operands.get(1)).isNull()) { + return isEffectivelyNotNull(operands.get(0)); } } return false; diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 3d36135ec6..546b222056 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -667,6 +667,13 @@ class SqlToRelConverterTest extends SqlToRelTestBase { sql(sql).ok(); } + @Test void testAggFilterWithInSubQuery() { + final String sql = "select\n" + + " count(*) filter (where empno in (select deptno from empnullables))\n" + + "from empnullables"; + sql(sql).withExpand(false).ok(); + } + @Test void testFakeStar() { sql("SELECT * FROM (VALUES (0, 0)) AS T(A, \"*\")").ok(); } @@ -4652,6 +4659,12 @@ class SqlToRelConverterTest extends SqlToRelTestBase { sql(sql).ok(); } + @Test void testProjectInSubQueryWithIsTruePredicate() { + final String sql = "select deptno in (select deptno from empnullables) is true\n" + + "from empnullables"; + sql(sql).withExpand(false).ok(); + } + @Test void testProjectAggregatesIgnoreNullsAndNot() { final String sql = "select lead(sal, 4) IGNORE NULLS, lead(sal, 4) over (w)\n" + "from emp window w as (order by empno)"; diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index d1581c2922..68aeb4885c 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -86,6 +86,23 @@ group by deptno]]> LogicalAggregate(group=[{0}], EXPR$1=[SUM($1) FILTER $2], EXPR$2=[COUNT()]) LogicalProject(DEPTNO=[$7], $f1=[*($5, 2)], $f2=[SEARCH($0, Sarg[(-∞..1), (1..2), (2..+∞)])]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> + <TestCase name="testAggFilterWithInSubQuery"> + <Resource name="sql"> + <![CDATA[select + count(*) filter (where empno in (select deptno from empnullables)) +from empnullables]]> + </Resource> + <Resource name="plan"> + <![CDATA[ +LogicalAggregate(group=[{}], EXPR$0=[COUNT() FILTER $0]) + LogicalProject($f0=[IS TRUE(IN($0, { +LogicalProject(DEPTNO=[$7]) + LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) +}))]) + LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) ]]> </Resource> </TestCase> @@ -5871,6 +5888,21 @@ GROUP BY empno]]> LogicalAggregate(group=[{0}], EXPR$1=[COUNT(DISTINCT $1)], EXPR$2=[COUNT(APPROXIMATE DISTINCT $1)]) LogicalProject(EMPNO=[$0], ENAME=[$1]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> + <TestCase name="testProjectInSubQueryWithIsTruePredicate"> + <Resource name="sql"> + <![CDATA[select deptno in (select deptno from empnullables) is true +from empnullables]]> + </Resource> + <Resource name="plan"> + <![CDATA[ +LogicalProject(EXPR$0=[IS TRUE(IN($7, { +LogicalProject(DEPTNO=[$7]) + LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) +}))]) + LogicalTableScan(table=[[CATALOG, SALES, EMPNULLABLES]]) ]]> </Resource> </TestCase> diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index 1cd28283c9..007e52cce0 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -3573,4 +3573,42 @@ or 20 in ( !ok +# Test case for [CALCITE-5691] IN sub-query inside FILTER clause throws IndexOutOfBoundsException +select + count(*) filter (where empno in (select deptno from emp)) +from emp; ++--------+ +| EXPR$0 | ++--------+ +| 0 | ++--------+ +(1 row) + +!ok + +# Test case for [CALCITE-5691] IN sub-query inside FILTER clause throws IndexOutOfBoundsException +select deptno in (select deptno from emp) is true +from emp; ++--------+ +| EXPR$0 | ++--------+ +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | +| true | ++--------+ +(14 rows) + +!ok + # End sub-query.iq