diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java index ed6d52491a42..989ab0a2633b 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -1984,6 +1984,13 @@ public RelNode convertToSingleValueSubq( case ALL: return RexUtil.composeConjunction(rexBuilder, comparisons, true); case NOT_IN: + if (comparisons.stream().allMatch(c -> c.getKind() == SqlKind.EQUALS)) { + final List notEqualsComparisons = + Util.transform(comparisons, + c -> rexBuilder.makeCall(SqlStdOperatorTable.NOT_EQUALS, + ((RexCall) c).getOperands())); + return RexUtil.composeConjunction(rexBuilder, notEqualsComparisons, false); + } return rexBuilder.makeCall(SqlStdOperatorTable.NOT, RexUtil.composeDisjunction(rexBuilder, comparisons)); case IN: 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 1d5833c5160b..ccedb3fb7f3c 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -945,6 +945,16 @@ public static void checkActualAndReferenceFiles() { sql(sql).ok(); } + @Test void testNotInSingleValue() { + final String sql = "select * from emp where deptno not in (10)"; + sql(sql).ok(); + } + + @Test void testNotInMultiValue() { + final String sql = "select * from emp where deptno not in (10, 20)"; + sql(sql).ok(); + } + @Test void testAggFilterWithInSubQuery() { final String sql = "select\n" + " count(*) filter (where empno in (select deptno from empnullables))\n" diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index 4eae45cc8aa3..b8a0a17e1f31 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -6582,7 +6582,7 @@ join sales.emp e on e.deptno = d.deptno and d.deptno not in (4, 6)]]> ($7, 4), <>($7, 6))], joinType=[inner]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -6591,7 +6591,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ ($7, 4), <>($7, 6))]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) LogicalFilter(condition=[SEARCH($7, Sarg[(-∞..4), (4..6), (6..+∞)])]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) 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 90b3c09a2432..af317223919c 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -6015,7 +6015,7 @@ LogicalProject(EXPR$0=[COMPARE_STRINGS_OR_NUMERIC_VALUES(1, 1)]) ($7, 10), <>($7, 20)), false, NOT(false), AND(<>($7, 30), <>($7, 40)))]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -6027,7 +6027,7 @@ LogicalProject(EMPNO=[$0]) ($7, 10), <>($7, 20)), NOT(true))]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -6039,7 +6039,7 @@ LogicalProject(EMPNO=[$0]) ($7, 10), <>($7, 20))):BOOLEAN, null:BOOLEAN)]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -6059,6 +6059,30 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$ LogicalProject($f0=[true]) LogicalFilter(condition=[=($cor0.DEPTNO, $0)]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) +]]> + + + + + + + + ($7, 10), <>($7, 20))]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + + + ($7, 10)]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]>