Skip to content

Commit

Permalink
[CALCITE-6650] Optimize the IN sub-query and SOME sub-query by Metada…
Browse files Browse the repository at this point in the history
…ta RowCount
  • Loading branch information
NobiGo committed Nov 11, 2024
1 parent edd6d11 commit f347fba
Show file tree
Hide file tree
Showing 4 changed files with 368 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ private static RexNode rewriteCollection(RexSubQuery e,
*/
private static RexNode rewriteSome(RexSubQuery e, Set<CorrelationId> variablesSet,
RelBuilder builder, int subQueryIndex) {
// If the sub-query is guaranteed to return 0 row, just return
// FALSE.
final RelMetadataQuery mq = e.rel.getCluster().getMetadataQuery();
final Double maxRowCount = mq.getMaxRowCount(e.rel);
if (maxRowCount != null && maxRowCount <= 0D) {
return builder.getRexBuilder().makeLiteral(Boolean.FALSE, e.getType(), true);
}
// Most general case, where the left and right keys might have nulls, and
// caller requires 3-valued logic return.
//
Expand Down Expand Up @@ -459,11 +466,11 @@ private static RexNode rewriteExists(RexSubQuery e, Set<CorrelationId> variables
// TRUE.
final RelMetadataQuery mq = e.rel.getCluster().getMetadataQuery();
final Double minRowCount = mq.getMinRowCount(e.rel);
if (minRowCount != null && minRowCount >= 1D) {
if (minRowCount != null && minRowCount > 0D) {
return builder.literal(true);
}
final Double maxRowCount = mq.getMaxRowCount(e.rel);
if (maxRowCount != null && maxRowCount < 1D) {
if (maxRowCount != null && maxRowCount <= 0D) {
return builder.literal(false);
}
builder.push(e.rel);
Expand Down Expand Up @@ -555,6 +562,13 @@ private static RexNode rewriteUnique(RexSubQuery e, RelBuilder builder) {
*/
private static RexNode rewriteIn(RexSubQuery e, Set<CorrelationId> variablesSet,
RelOptUtil.Logic logic, RelBuilder builder, int offset, int subQueryIndex) {
// If the sub-query is guaranteed to return 0 row, just return
// FALSE.
final RelMetadataQuery mq = e.rel.getCluster().getMetadataQuery();
final Double maxRowCount = mq.getMaxRowCount(e.rel);
if (maxRowCount != null && maxRowCount <= 0D) {
return builder.getRexBuilder().makeLiteral(Boolean.FALSE, e.getType(), true);
}
// Most general case, where the left and right keys might have nulls, and
// caller requires 3-valued logic return.
//
Expand Down
46 changes: 46 additions & 0 deletions core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5049,6 +5049,52 @@ private void checkEmptyJoin(RelOptFixture f) {
sql(sql).withSubQueryRules().check();
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-6650">[CALCITE-6650]
* Optimize the IN sub-query and SOME sub-query
* by Metadata RowCount</a>. */
@Test void testInWithNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where deptno in (\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

@Test void testNotInWithNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where deptno not in (\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

@Test void testSomeWithGreaterThanNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where deptno > some(\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

@Test void testSomeWithLessThanOrEqualNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where deptno <= some(\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

@Test void testUniqueWithNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where unique(\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

@Test void testNotUniqueWithNoRowSubQuery() {
final String sql = "select * from dept as d\n"
+ "where not unique(\n"
+ " select deptno from emp e where false)";
sql(sql).withSubQueryRules().check();
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-4848">[CALCITE-4848]
* Adding a HAVING condition to a query with a dynamic parameter makes the result always empty
Expand Down
144 changes: 144 additions & 0 deletions core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5081,6 +5081,30 @@ LogicalUnion(all=[true])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalProject(EXPR$0=[LOWER($1)])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
<TestCase name="testInWithNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where deptno in (
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[IN($0, {
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
})])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>
Expand Down Expand Up @@ -7724,6 +7748,30 @@ LogicalProject(USER=[USER])
LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)])
LogicalProject(NAME=[$1], DEPTNO=[$0])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
<TestCase name="testNotInWithNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where deptno not in (
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[NOT(IN($0, {
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
}))])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
Expand Down Expand Up @@ -7762,6 +7810,30 @@ LogicalProject(NAME=[$1], DEPTNO=[$0], EXPR$2=[$2])
LogicalFilter(condition=[=($0, 0)])
LogicalWindow(window#0=[window(partition {1} aggs [COUNT()])])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
<TestCase name="testNotUniqueWithNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where not unique(
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[NOT(UNIQUE({
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
}))])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>
Expand Down Expand Up @@ -14508,6 +14580,54 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
LogicalAggregate(group=[{0}])
LogicalProject(NAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
<TestCase name="testSomeWithGreaterThanNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where deptno > some(
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[> SOME($0, {
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
})])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>
<TestCase name="testSomeWithLessThanOrEqualNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where deptno <= some(
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[<= SOME($0, {
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
})])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalValues(tuples=[[]])
]]>
</Resource>
</TestCase>
Expand Down Expand Up @@ -16888,6 +17008,30 @@ LogicalUnion(all=[true])
<Resource name="planAfter">
<![CDATA[
LogicalValues(tuples=[[{ 5 }, { 5 }]])
]]>
</Resource>
</TestCase>
<TestCase name="testUniqueWithNoRowSubQuery">
<Resource name="sql">
<![CDATA[select * from dept as d
where unique(
select deptno from emp e where false)]]>
</Resource>
<Resource name="planBefore">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalFilter(condition=[UNIQUE({
LogicalProject(DEPTNO=[$7])
LogicalFilter(condition=[false])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
})])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
<Resource name="planAfter">
<![CDATA[
LogicalProject(DEPTNO=[$0], NAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
Expand Down
Loading

0 comments on commit f347fba

Please sign in to comment.