This is an automated email from the ASF dual-hosted git repository.
suibianwanwan 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 fd57e660f2 [CALCITE-7010] The well-known count bug
fd57e660f2 is described below
commit fd57e660f2dd76af0f68b36a09be6c0a9cd9ca0e
Author: suibianwanwan <[email protected]>
AuthorDate: Sat Jun 21 18:14:59 2025 +0800
[CALCITE-7010] The well-known count bug
---
.../apache/calcite/sql2rel/RelDecorrelator.java | 303 ++++++++++++++++++---
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 14 -
.../calcite/sql2rel/RelDecorrelatorTest.java | 34 ++-
.../org/apache/calcite/test/RelOptRulesTest.xml | 50 ++--
.../apache/calcite/test/SqlToRelConverterTest.xml | 162 ++++++-----
core/src/test/resources/sql/blank.iq | 16 +-
core/src/test/resources/sql/sub-query.iq | 214 +++++++++------
7 files changed, 554 insertions(+), 239 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index 06312d67b0..b5500c871b 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -45,7 +45,6 @@
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.Sort;
-import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rel.logical.LogicalAggregate;
import org.apache.calcite.rel.logical.LogicalCorrelate;
import org.apache.calcite.rel.logical.LogicalFilter;
@@ -113,9 +112,11 @@
import org.slf4j.Logger;
import java.math.BigDecimal;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -160,11 +161,16 @@ public class RelDecorrelator implements ReflectiveVisitor
{
// map built during translation
protected CorelMap cm;
+ /** Stack maintaining visible Frames to the currently invoked RelNode during
top-down traversal.
+ * Each entry maps a CorrelationId to the Frame where its correlated
variables originate. */
+ protected final Deque<Pair<CorrelationId, Frame>> frameStack = new
ArrayDeque<>();
+
@SuppressWarnings("method.invocation.invalid")
protected final ReflectUtil.MethodDispatcher<@Nullable Frame> dispatcher =
ReflectUtil.<RelNode, @Nullable Frame>createMethodDispatcher(
Frame.class, getVisitor(), "decorrelateRel",
RelNode.class,
+ boolean.class,
boolean.class);
// The rel which is being visited
@@ -332,7 +338,7 @@ protected RelNode decorrelate(RelNode root) {
// Perform decorrelation.
map.clear();
- final Frame frame = getInvoke(root, false, null);
+ final Frame frame = getInvoke(root, false, null, true);
if (frame != null) {
// Check if the frame has more fields than the original and discard the
extra ones
RelNode result = frame.r;
@@ -498,14 +504,16 @@ protected RexNode removeCorrelationExpr(
}
/** Fallback if none of the other {@code decorrelateRel} methods match. */
- public @Nullable Frame decorrelateRel(RelNode rel, boolean isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(RelNode rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
RelNode newRel = rel.copy(rel.getTraitSet(), rel.getInputs());
if (!rel.getInputs().isEmpty()) {
List<RelNode> oldInputs = rel.getInputs();
List<RelNode> newInputs = new ArrayList<>();
for (int i = 0; i < oldInputs.size(); ++i) {
- final Frame frame = getInvoke(oldInputs.get(i), isCorVarDefined, rel);
+ final Frame frame =
+ getInvoke(oldInputs.get(i), isCorVarDefined, rel,
parentPropagatesNullValues);
if (frame == null || !frame.corDefOutputs.isEmpty()) {
// if input is not rewritten, or if it produces correlated
// variables, terminate rewrite
@@ -526,7 +534,8 @@ protected RexNode removeCorrelationExpr(
ImmutableSortedMap.of());
}
- public @Nullable Frame decorrelateRel(Sort rel, boolean isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Sort rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
//
// Rewrite logic:
//
@@ -543,7 +552,7 @@ protected RexNode removeCorrelationExpr(
// need to call propagateExpr.
final RelNode oldInput = rel.getInput();
- final Frame frame = getInvoke(oldInput, isCorVarDefined, rel);
+ final Frame frame = getInvoke(oldInput, isCorVarDefined, rel, true);
if (frame == null) {
// If input has not been rewritten, do not rewrite this rel.
return null;
@@ -581,16 +590,13 @@ protected RexNode removeCorrelationExpr(
return register(rel, newSort, frame.oldToNewOutputs, frame.corDefOutputs);
}
- public @Nullable Frame decorrelateRel(Values rel, boolean isCorVarDefined) {
- // There are no inputs, so rel does not need to be changed.
- return null;
- }
-
- public @Nullable Frame decorrelateRel(LogicalAggregate rel, boolean
isCorVarDefined) {
- return decorrelateRel((Aggregate) rel, isCorVarDefined);
+ public @Nullable Frame decorrelateRel(LogicalAggregate rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
+ return decorrelateRel((Aggregate) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(Aggregate rel, boolean
isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Aggregate rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
//
// Rewrite logic:
//
@@ -604,7 +610,7 @@ protected RexNode removeCorrelationExpr(
assert !cm.mapRefRelToCorRef.containsKey(rel);
final RelNode oldInput = rel.getInput();
- final Frame frame = getInvoke(oldInput, isCorVarDefined, rel);
+ final Frame frame = getInvoke(oldInput, isCorVarDefined, rel,
parentPropagatesNullValues);
if (frame == null) {
// If input has not been rewritten, do not rewrite this rel.
return null;
@@ -782,11 +788,196 @@ protected RexNode removeCorrelationExpr(
RelNode newRel = relBuilder.build();
+ for (AggregateCall aggCall : rel.getAggCallList()) {
+ if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
+ parentPropagatesNullValues = false;
+ break;
+ }
+ }
+
+ if (rel.getGroupType() == Aggregate.Group.SIMPLE
+ && rel.getGroupSet().isEmpty()
+ && !frame.corDefOutputs.isEmpty()
+ && !parentPropagatesNullValues) {
+ newRel = rewriteScalarAggregate(rel, newRel, outputMap, corDefOutputs);
+ }
+
// Aggregate does not change input ordering so corVars will be
// located at the same position as the input newProject.
return register(rel, newRel, outputMap, corDefOutputs);
}
+ /**
+ * Special case where the group by is static (i.e., aggregation functions
without group by).
+ *
+ * <p>Background:
+ * For the query:
+ * SELECT SUM(salary), COUNT(name) FROM A;
+ * When table A is empty, it returns [null, 0].
+ * But for
+ * SELECT SUM(salary), COUNT(name) FROM A group by id
+ * When table A is empty, it returns empty. This causes result mismatch.
+ * In the general decorrelation framework, we add corVar as an additional
groupKey to
+ * rewrite Correlate as JOIN. (See the code above for details) This means
that when the input
+ * is empty, the result produced using a JOIN is incorrect.
+ *
+ * <p>We refer to this situation as: `The well-known count bug`,
+ * More details about this issue: Optimization of Nested SQL Queries
Revisited
+ * (https://dl.acm.org/doi/pdf/10.1145/38714.38723)
+ *
+ * <p>To handle this situation, we using a LEFT JOIN to ensure that an
output is always produced.
+ *
+ * <p>Given the SQL:
+ * SELECT deptno FROM dept d
+ * WHERE 0 = (SELECT COUNT(*) FROM emp e WHERE d.deptno = e.deptno)
+ * Corresponding plan:
+ * LogicalProject(DEPTNO=[$0])
+ * LogicalCorrelate(correlation=[$cor0], joinType=[inner],
requiredColumns=[{0}])
+ * LogicalProject(DEPTNO=[$0])
+ * LogicalTableScan(table=[[scott, DEPT]])
+ * LogicalProject(cs=[true])
+ * LogicalFilter(condition=[=(0, $0)])
+ * LogicalAggregate(group=[{}], EXPR$0=[COUNT()])
+ * LogicalFilter(condition=[=($cor0.DEPTNO, $7)])
+ * LogicalTableScan(table=[[scott, EMP]])
+ *
+ * <p>Rewriting this as:
+ * SELECT d.deptno FROM dept d
+ * JOIN (
+ * SELECT true, e.deptno FROM emp e WHERE e.deptno IS NOT NULL
+ * GROUP BY e.deptno HAVING COUNT(*) = 0
+ * ) AS d0 ON d.deptno = d0.deptno
+ * produces an incorrect result.
+ * Corresponding plan:
+ * LogicalProject(DEPTNO=[$0])
+ * LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+ * LogicalProject(DEPTNO=[$0])
+ * LogicalTableScan(table=[[scott, DEPT]])
+ * LogicalProject(cs=[true], DEPTNO=[$0])
+ * LogicalFilter(condition=[=(0, $1)])
+ * LogicalAggregate(group=[{0}], EXPR$0=[COUNT()]) // corresponds
to {@code oldRel}
+ * LogicalProject(DEPTNO=[$7])
+ * LogicalFilter(condition=[IS NOT NULL($7)])
+ * LogicalTableScan(table=[[scott, EMP]])
+ * We can clearly observe that due to the presence of the GROUP BY clause,
+ * COUNT(*) = 0 will never evaluate to true, since rows with zero records
won't appear
+ * in the GROUP BY results. This produced incorrect results.
+ *
+ * <p>Rewrite Aggregate as:
+ * SELECT d.deptno FROM dept d
+ * JOIN (
+ * SELECT true AS cs, deptno
+ * FROM (
+ * SELECT d2.deptno,
+ * CASE WHEN cnt0 IS NOT NULL THEN cnt0 ELSE 0 END AS cnt
+ * FROM (SELECT deptno FROM dept GROUP BY deptno) d2
+ * LEFT JOIN (
+ * SELECT deptno, COUNT(e.empno) cnt0
+ * FROM emp
+ * WHERE deptno IS NOT NULL
+ * GROUP BY deptno) e
+ * ON d2.deptno IS NOT DISTINCT FROM e.deptno
+ * ) AS case_count
+ * WHERE cnt = 0
+ * ) AS d0 ON d.deptno = d0.deptno
+ * Corresponding plan:
+ * [01] LogicalProject(DEPTNO=[$0])
+ * [02] LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+ * [03] LogicalProject(DEPTNO=[$0])
+ * [04] LogicalTableScan(table=[[scott, DEPT]])
+ * [05] LogicalProject(cs=[true], DEPTNO=[$0])
+ * [06] LogicalFilter(condition=[=(0, $1)])
+ * [07] LogicalProject(DEPTNO=[$0], EXPR$0=[CASE(IS NOT NULL($2),
$2, 0)])
+ * [08] LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ * [09] LogicalAggregate(group=[{0}])
+ * [10] LogicalProject(DEPTNO=[$0])
+ * [11] LogicalTableScan(table=[[scott, DEPT]])
+ * [12] LogicalAggregate(group=[{0}], EXPR$0=[COUNT()])
+ * [13] LogicalProject(DEPTNO=[$7])
+ * [14] LogicalFilter(condition=[IS NOT NULL($7)])
+ * [15] LogicalTableScan(table=[[scott, EMP]])
+ *
+ * <p>Here we perform an early join, preserving all possible CorVar sets
from the outer scope
+ * and their corresponding aggregation results. This ensures that for any
row from the left
+ * input of the Correlation, there is always an aggregation result available
for join output.
+ *
+ * <p>Implementation based on: Improving Unnesting of Complex Queries
+ *
(https://dl.gi.de/server/api/core/bitstreams/c1918e8c-6a87-4da2-930a-bfed289f2388/content)
+ */
+ private RelNode rewriteScalarAggregate(Aggregate oldRel,
+ RelNode newRel,
+ Map<Integer, Integer> outputMap,
+ NavigableMap<CorDef, Integer> corDefOutputs) {
+ final Pair<CorrelationId, Frame> outerFramePair =
requireNonNull(this.frameStack.peek());
+ final Frame outFrame = outerFramePair.right;
+ RexBuilder rexBuilder = relBuilder.getRexBuilder();
+
+ int groupKeySize = (int) corDefOutputs.keySet().stream()
+ .filter(a -> a.corr.equals(outerFramePair.left))
+ .count();
+ List<RelDataTypeField> newRelFields = newRel.getRowType().getFieldList();
+ ImmutableBitSet.Builder corFieldBuilder = ImmutableBitSet.builder();
+
+ // Here we record the mapping between the original index and the new
project.
+ // For the count, we map it as `case when x is null then 0 else x`.
+ final Map<Integer, RexNode> newProjectMap = new HashMap<>();
+ final List<RexNode> conditions = new ArrayList<>();
+ for (Map.Entry<CorDef, Integer> corDefOutput : corDefOutputs.entrySet()) {
+ CorDef corDef = corDefOutput.getKey();
+ Integer corIndex = corDefOutput.getValue();
+ if (corDef.corr.equals(outerFramePair.left)) {
+ int newIdx =
requireNonNull(outFrame.oldToNewOutputs.get(corDef.field));
+ corFieldBuilder.set(newIdx);
+
+ RelDataType type =
outFrame.r.getRowType().getFieldList().get(newIdx).getType();
+ RexNode left = new RexInputRef(corFieldBuilder.cardinality() - 1,
type);
+ newProjectMap.put(corIndex + groupKeySize, left);
+ conditions.add(
+ relBuilder.isNotDistinctFrom(left,
+ new RexInputRef(corIndex + groupKeySize,
+ newRelFields.get(corIndex).getType())));
+ }
+ }
+
+ ImmutableBitSet groupSet = corFieldBuilder.build();
+ // Build [09] LogicalAggregate(group=[{0}]) to obtain the distinct set of
+ // corVar from outFrame.
+ relBuilder.push(outFrame.r)
+ .aggregate(relBuilder.groupKey(groupSet));
+
+ // Build [08] LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ // to ensure each corVar's aggregate result is output.
+ final RelNode join = relBuilder.push(newRel)
+ .join(JoinRelType.LEFT, conditions).build();
+
+ for (int i1 = 0; i1 < oldRel.getAggCallList().size(); i1++) {
+ AggregateCall aggCall = oldRel.getAggCallList().get(i1);
+ if (aggCall.getAggregation() instanceof SqlCountAggFunction) {
+ int index = requireNonNull(outputMap.get(i1 +
oldRel.getGroupSet().size()));
+ final RexInputRef ref = RexInputRef.of(index + groupKeySize,
join.getRowType());
+ RexNode specificCountValue =
+ rexBuilder.makeCall(SqlStdOperatorTable.CASE,
+ ImmutableList.of(relBuilder.isNotNull(ref), ref,
relBuilder.literal(0)));
+ newProjectMap.put(ref.getIndex(), specificCountValue);
+ }
+ }
+
+ final List<RexNode> newProjects = new ArrayList<>();
+ for (int index : ImmutableBitSet.range(groupKeySize,
join.getRowType().getFieldCount())) {
+ if (newProjectMap.containsKey(index)) {
+ newProjects.add(requireNonNull(newProjectMap.get(index)));
+ } else {
+ newProjects.add(RexInputRef.of(index, join.getRowType()));
+ }
+ }
+
+ // Build [07] LogicalProject(DEPTNO=[$0], EXPR$0=[CASE(IS NOT NULL($2),
$2, 0)])
+ // to handle COUNT function by converting nulls to zero.
+ return relBuilder.push(join)
+ .project(newProjects, newRel.getRowType().getFieldNames())
+ .build();
+ }
+
/**
* Shift the mapping to fixed offset from the {@code startIndex}.
*
@@ -803,8 +994,15 @@ private static void shiftMapping(Map<Integer, Integer>
mapping, int startIndex,
}
}
- public @Nullable Frame getInvoke(RelNode r, boolean isCorVarDefined,
@Nullable RelNode parent) {
- final Frame frame = dispatcher.invoke(r, isCorVarDefined);
+ /**
+ * Invokes decorrelation logic for a given relational expression.
+ *
+ * @param parentPropagatesNullValues True if the parent RelNode produces null
+ * when all of its inputs fields are null.
+ */
+ public @Nullable Frame getInvoke(RelNode r, boolean isCorVarDefined,
+ @Nullable RelNode parent, boolean parentPropagatesNullValues) {
+ final Frame frame = dispatcher.invoke(r, isCorVarDefined,
parentPropagatesNullValues);
currentRel = parent;
if (frame != null) {
map.put(r, frame);
@@ -964,19 +1162,26 @@ private static void shiftMapping(Map<Integer, Integer>
mapping, int startIndex,
return null;
}
- public @Nullable Frame decorrelateRel(LogicalProject rel, boolean
isCorVarDefined) {
- return decorrelateRel((Project) rel, isCorVarDefined);
+ public @Nullable Frame decorrelateRel(LogicalProject rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
+ return decorrelateRel((Project) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(Project rel, boolean isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Project rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
//
// Rewrite logic:
//
// 1. Pass along any correlated variables coming from the input.
//
+ for (RexNode project : rel.getProjects()) {
+ if (!Strong.isStrong(project)) {
+ parentPropagatesNullValues = false;
+ }
+ }
final RelNode oldInput = rel.getInput();
- Frame frame = getInvoke(oldInput, isCorVarDefined, rel);
+ Frame frame = getInvoke(oldInput, isCorVarDefined, rel,
parentPropagatesNullValues);
if (frame == null) {
// If input has not been rewritten, do not rewrite this rel.
return null;
@@ -1326,25 +1531,29 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
&& type.getPrecision() >= type1.getPrecision();
}
- public @Nullable Frame decorrelateRel(LogicalSnapshot rel, boolean
isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(LogicalSnapshot rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
if (RexUtil.containsCorrelation(rel.getPeriod())) {
return null;
}
- return decorrelateRel((RelNode) rel, isCorVarDefined);
+ return decorrelateRel((RelNode) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(LogicalTableFunctionScan rel, boolean
isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(LogicalTableFunctionScan rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
if (RexUtil.containsCorrelation(rel.getCall())) {
return null;
}
- return decorrelateRel((RelNode) rel, isCorVarDefined);
+ return decorrelateRel((RelNode) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(LogicalFilter rel, boolean
isCorVarDefined) {
- return decorrelateRel((Filter) rel, isCorVarDefined);
+ public @Nullable Frame decorrelateRel(LogicalFilter rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
+ return decorrelateRel((Filter) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(Filter rel, boolean isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Filter rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
//
// Rewrite logic:
//
@@ -1362,7 +1571,7 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
//
final RelNode oldInput = rel.getInput();
- Frame frame = getInvoke(oldInput, isCorVarDefined, rel);
+ Frame frame = getInvoke(oldInput, isCorVarDefined, rel,
parentPropagatesNullValues);
if (frame == null) {
// If input has not been rewritten, do not rewrite this rel.
return null;
@@ -1393,11 +1602,13 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
frame.corDefOutputs);
}
- public @Nullable Frame decorrelateRel(LogicalCorrelate rel, boolean
isCorVarDefined) {
- return decorrelateRel((Correlate) rel, isCorVarDefined);
+ public @Nullable Frame decorrelateRel(LogicalCorrelate rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
+ return decorrelateRel((Correlate) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(Correlate rel, boolean
isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Correlate rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
//
// Rewrite logic:
//
@@ -1411,15 +1622,17 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
final RelNode oldLeft = rel.getInput(0);
final RelNode oldRight = rel.getInput(1);
- final Frame leftFrame = getInvoke(oldLeft, isCorVarDefined, rel);
- final Frame rightFrame = getInvoke(oldRight, true, rel);
-
- if (leftFrame == null || rightFrame == null) {
- // If any input has not been rewritten, do not rewrite this rel.
+ final Frame leftFrame = getInvoke(oldLeft, isCorVarDefined, rel,
parentPropagatesNullValues);
+ if (leftFrame == null) {
+ // If input has not been rewritten, do not rewrite this rel.
return null;
}
- if (rightFrame.corDefOutputs.isEmpty()) {
+ frameStack.push(Pair.of(rel.getCorrelationId(), leftFrame));
+ final Frame rightFrame = getInvoke(oldRight, true, rel,
parentPropagatesNullValues);
+ frameStack.pop();
+
+ if (rightFrame == null || rightFrame.corDefOutputs.isEmpty()) {
return null;
}
@@ -1504,16 +1717,18 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
return register(rel, newJoin, mapOldToNewOutputs, corDefOutputs);
}
- public @Nullable Frame decorrelateRel(LogicalJoin rel, boolean
isCorVarDefined) {
- return decorrelateRel((Join) rel, isCorVarDefined);
+ public @Nullable Frame decorrelateRel(LogicalJoin rel, boolean
isCorVarDefined,
+ boolean parentPropagatesNullValues) {
+ return decorrelateRel((Join) rel, isCorVarDefined,
parentPropagatesNullValues);
}
- public @Nullable Frame decorrelateRel(Join rel, boolean isCorVarDefined) {
+ public @Nullable Frame decorrelateRel(Join rel, boolean isCorVarDefined,
+ boolean parentPropagatesNullValues) {
// For SEMI/ANTI join decorrelate it's input directly,
// because the correlate variables can only be propagated from
// the left side, which is not supported yet.
if (!rel.getJoinType().projectsRight()) {
- return decorrelateRel((RelNode) rel, isCorVarDefined);
+ return decorrelateRel((RelNode) rel, isCorVarDefined,
parentPropagatesNullValues);
}
//
// Rewrite logic:
@@ -1525,8 +1740,8 @@ private static boolean isWidening(RelDataType type,
RelDataType type1) {
final RelNode oldLeft = rel.getInput(0);
final RelNode oldRight = rel.getInput(1);
- final Frame leftFrame = getInvoke(oldLeft, isCorVarDefined, rel);
- final Frame rightFrame = getInvoke(oldRight, isCorVarDefined, rel);
+ final Frame leftFrame = getInvoke(oldLeft, isCorVarDefined, rel,
parentPropagatesNullValues);
+ final Frame rightFrame = getInvoke(oldRight, isCorVarDefined, rel,
parentPropagatesNullValues);
if (leftFrame == null || rightFrame == null) {
// If any input has not been rewritten, do not rewrite this rel.
diff --git
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 7872eaa485..968f3ae80e 100644
---
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -7505,20 +7505,6 @@ private void checkLiteral2(String expression, String
expected) {
callsUnparseCallOnSqlSelect[0], is(true));
}
- @Test void testCorrelate() {
- final String sql = "select d.\"department_id\", d_plusOne "
- + "from \"department\" as d, "
- + " lateral (select d.\"department_id\" + 1 as d_plusOne"
- + " from (values(true)))";
-
- final String expected = "SELECT \"$cor0\".\"department_id\",
\"t1\".\"D_PLUSONE\"\n"
- + "FROM (SELECT \"department_id\", \"department_description\",
\"department_id\" + 1 AS \"$f2\"\n"
- + "FROM \"foodmart\".\"department\") AS \"$cor0\",\n"
- + "LATERAL (SELECT \"$cor0\".\"$f2\" AS \"D_PLUSONE\"\n"
- + "FROM (VALUES (TRUE)) AS \"t\" (\"EXPR$0\")) AS \"t1\"";
- sql(sql).ok(expected);
- }
-
/** Test case for
* <a
href="https://issues.apache.org/jira/browse/CALCITE-3651">[CALCITE-3651]
* NullPointerException when convert relational algebra that correlates
TableFunctionScan</a>. */
diff --git
a/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
b/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
index ab25202c24..40b6212778 100644
--- a/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
+++ b/core/src/test/java/org/apache/calcite/sql2rel/RelDecorrelatorTest.java
@@ -269,17 +269,23 @@ public static Frameworks.ConfigBuilder config() {
// Verify plan
final String planAfter = ""
+ "LogicalProject(EXPR$0=[1])\n"
- + " LogicalJoin(condition=[AND(=($0, $2), >($1, $3))],
joinType=[inner])\n"
+ + " LogicalJoin(condition=[AND(IS NOT DISTINCT FROM($0, $2), >($1,
$3))], joinType=[inner])\n"
+ " LogicalAggregate(group=[{0}], TOTAL=[SUM($1)])\n"
+ " LogicalProject(DEPTNO=[$7], SAL=[$5])\n"
+ " LogicalTableScan(table=[[scott, EMP]])\n"
- + " LogicalAggregate(group=[{0}], EXPR$0=[AVG($1)])\n"
- + " LogicalProject(DEPTNO=[$0], TOTAL=[$1])\n"
- + " LogicalAggregate(group=[{0}], TOTAL=[SUM($1)])\n"
- + " LogicalProject(DEPTNO=[$0], SAL=[$1])\n"
- + " LogicalFilter(condition=[IS NOT NULL($0)])\n"
- + " LogicalProject(DEPTNO=[$7], SAL=[$5])\n"
- + " LogicalTableScan(table=[[scott, EMP]])\n";
+ + " LogicalProject(DEPTNO=[$0], EXPR$0=[$2])\n"
+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])\n"
+ + " LogicalProject(DEPTNO=[$0])\n"
+ + " LogicalAggregate(group=[{0}], TOTAL=[SUM($1)])\n"
+ + " LogicalProject(DEPTNO=[$7], SAL=[$5])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n"
+ + " LogicalAggregate(group=[{0}], EXPR$0=[AVG($1)])\n"
+ + " LogicalProject(DEPTNO=[$0], TOTAL=[$1])\n"
+ + " LogicalAggregate(group=[{0}], TOTAL=[SUM($1)])\n"
+ + " LogicalProject(DEPTNO=[$0], SAL=[$1])\n"
+ + " LogicalFilter(condition=[IS NOT NULL($0)])\n"
+ + " LogicalProject(DEPTNO=[$7], SAL=[$5])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n";
assertThat(after, hasTree(planAfter));
}
@@ -360,11 +366,15 @@ public static Frameworks.ConfigBuilder config() {
RelDecorrelator.decorrelateQuery(original, builder, noRules);
final String planDecorrelatedNoRules = ""
+ "LogicalProject(EXPR$0=[ROW($9, $1)])\n"
- + " LogicalJoin(condition=[=($7, $8)], joinType=[left])\n"
+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($7, $8)],
joinType=[left])\n"
+ " LogicalTableScan(table=[[scott, EMP]])\n"
- + " LogicalAggregate(group=[{0}], agg#0=[SINGLE_VALUE($1)])\n"
- + " LogicalProject(DEPTNO1=[$0], DEPTNO=[$0])\n"
- + " LogicalTableScan(table=[[scott, DEPT]])\n";
+ + " LogicalProject(DEPTNO1=[$0], $f1=[$2])\n"
+ + " LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])\n"
+ + " LogicalAggregate(group=[{7}])\n"
+ + " LogicalTableScan(table=[[scott, EMP]])\n"
+ + " LogicalAggregate(group=[{0}], agg#0=[SINGLE_VALUE($1)])\n"
+ + " LogicalProject(DEPTNO1=[$0], DEPTNO=[$0])\n"
+ + " LogicalTableScan(table=[[scott, DEPT]])\n";
assertThat(decorrelatedNoRules, hasTree(planDecorrelatedNoRules));
}
}
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 d74fdacc52..c00c7dc012 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -16122,10 +16122,13 @@ LogicalProject(EXPR$0=[CAST(OR(AND(IS TRUE(>($0,
$9)), IS NOT TRUE(OR(IS NULL($1
LogicalProject(EXPR$0=[CAST(OR(AND(IS TRUE(>($0, $9)), IS NOT TRUE(OR(IS
NULL($12), =($10, 0)))), AND(IS TRUE(>($10, $11)), null, IS NOT TRUE(OR(IS
NULL($12), =($10, 0))), IS NOT TRUE(>($0, $9))), AND(>($0, $9), IS NOT
TRUE(OR(IS NULL($12), =($10, 0))), IS NOT TRUE(>($0, $9)), IS NOT TRUE(>($10,
$11))))):BOOLEAN NOT NULL])
LogicalJoin(condition=[=($2, $13)], joinType=[left])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(m=[$1], c=[$2], d=[$2], trueLiteral=[$3], NAME=[$0])
- LogicalAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
- LogicalProject(NAME=[$1], DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(m=[$2], c=[CASE(IS NOT NULL($3), $3, 0)], d=[CASE(IS NOT
NULL($3), $3, 0)], trueLiteral=[$4], NAME=[$0])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])
+ LogicalAggregate(group=[{2}])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
+ LogicalProject(NAME=[$1], DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -19393,13 +19396,16 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2],
MGR=[$3], HIREDATE=[$4], SAL=[$
<Resource name="planAfter">
<![CDATA[
LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4],
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
- LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4],
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], m=[CAST($9):INTEGER],
c=[CAST($10):BIGINT], d=[CAST($11):BIGINT], trueLiteral=[CAST($12):BOOLEAN],
NAME=[CAST($13):VARCHAR(10)])
+ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4],
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], m=[$9], c=[CAST($10):BIGINT],
d=[CAST($11):BIGINT], trueLiteral=[$12], NAME=[CAST($13):VARCHAR(10)])
LogicalJoin(condition=[AND(=($2, $13), OR(AND(>($0, $9), IS NOT TRUE(OR(IS
NULL($12), =($10, 0)))), AND(>($0, $9), IS NOT TRUE(OR(IS NULL($12), =($10,
0))), IS NOT TRUE(>($0, $9)), IS NOT TRUE(>($10, $11)))))], joinType=[inner])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(m=[$1], c=[$2], d=[$2], trueLiteral=[$3], NAME=[$0])
- LogicalAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
- LogicalProject(NAME=[$1], DEPTNO=[$0])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(m=[$2], c=[CASE(IS NOT NULL($3), $3, 0)], d=[CASE(IS NOT
NULL($3), $3, 0)], trueLiteral=[$4], NAME=[$0])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)], joinType=[left])
+ LogicalAggregate(group=[{2}])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
+ LogicalProject(NAME=[$1], DEPTNO=[$0])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -19592,10 +19598,13 @@ LogicalProject(SAL=[$5])
LogicalJoin(condition=[AND(=($0, $12), =($2, $14))], joinType=[left])
LogicalJoin(condition=[=($2, $11)], joinType=[left])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(c=[$1], ck=[$1], NAME=[$0])
- LogicalAggregate(group=[{0}], c=[COUNT()])
- LogicalProject(NAME=[$1])
- LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalProject(c=[CASE(IS NOT NULL($2), $2, 0)], ck=[CASE(IS NOT
NULL($2), $2, 0)], NAME=[$0])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ LogicalAggregate(group=[{2}])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0}], c=[COUNT()])
+ LogicalProject(NAME=[$1])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
LogicalProject(DEPTNO=[$0], i=[true], NAME=[$1])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
@@ -19665,12 +19674,15 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2],
MGR=[$3], HIREDATE=[$4], SAL=[$
LogicalJoin(condition=[AND(=($0, $12), =($1, $14))], joinType=[left])
LogicalJoin(condition=[=($1, $11)], joinType=[left])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
- LogicalProject(c=[$1], ck=[$1], ENAME=[$0])
- LogicalAggregate(group=[{0}], c=[COUNT()])
- LogicalProject(ENAME=[$0])
- LogicalFilter(condition=[>($2, 2)])
- LogicalProject(ENAME=[$1], EMPNO=[$0], R=[$5])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(c=[CASE(IS NOT NULL($2), $2, 0)], ck=[CASE(IS NOT
NULL($2), $2, 0)], ENAME=[$0])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ LogicalAggregate(group=[{1}])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalAggregate(group=[{0}], c=[COUNT()])
+ LogicalProject(ENAME=[$0])
+ LogicalFilter(condition=[>($2, 2)])
+ LogicalProject(ENAME=[$1], EMPNO=[$0], R=[$5])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalProject(EMPNO=[$1], i=[true], ENAME=[$0])
LogicalFilter(condition=[>($2, 2)])
LogicalProject(ENAME=[$1], EMPNO=[$0], R=[$5])
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 3c3c646159..105ba0f9e4 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -1491,14 +1491,20 @@ LogicalAggregate(group=[{}], EXPR$0=[COUNT()],
EXPR$1=[SUM($0)])
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalProject(C=[$0], D=[$1], C0=[$2], F=[$3])
- LogicalProject(C=[$0], D=[$1], C0=[$4], F=[$5])
- LogicalCorrelate(correlation=[$cor3], joinType=[inner],
requiredColumns=[{2, 3}])
- LogicalProject(C=[$0], D=[$1], C0=[$0], $f3=[+($0, $1)])
- LogicalValues(tuples=[[{ 4, 5 }]])
- LogicalProject(C=[$cor3.C], F=[*($0, $cor3.C)])
- LogicalFilter(condition=[=($cor3.$f3, *($0, $cor3.C))])
+LogicalProject(C=[$0], D=[$1], C0=[$4], F=[$5])
+ LogicalJoin(condition=[AND(=($0, $6), =($3, $7))], joinType=[inner])
+ LogicalProject(C=[$0], D=[$1], C0=[$0], $f3=[+($0, $1)])
+ LogicalValues(tuples=[[{ 4, 5 }]])
+ LogicalProject(C=[$3], F=[*($0, $3)], C0=[$3], $f3=[$2])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalJoin(condition=[=($2, *($0, $1))], joinType=[inner])
LogicalValues(tuples=[[{ 2 }]])
+ LogicalAggregate(group=[{0, 1}])
+ LogicalProject(C=[$0], $f3=[+($0, $1)])
+ LogicalValues(tuples=[[{ 4, 5 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(C=[$0])
+ LogicalValues(tuples=[[{ 4, 5 }]])
]]>
</Resource>
</TestCase>
@@ -1515,18 +1521,19 @@ cross join lateral
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalProject(C=[$0], N=[$1])
- LogicalProject(C=[$0], N=[$3])
- LogicalCorrelate(correlation=[$cor1], joinType=[inner],
requiredColumns=[{1, 2}])
- LogicalProject(C=[$0], C0=[$0], $f2=[+($0, 1)])
- LogicalValues(tuples=[[{ 4 }]])
- LogicalProject(N=[$0])
- LogicalFilter(condition=[=($cor1.C, $0)])
- LogicalProject(EXPR$0=[+($0, $1)])
- LogicalJoin(condition=[=($0, $1)], joinType=[inner])
- LogicalValues(tuples=[[{ 2 }]])
- LogicalProject(EXPR$0=[$cor1.$f2])
- LogicalValues(tuples=[[{ 3 }]])
+LogicalProject(C=[$0], N=[$3])
+ LogicalJoin(condition=[AND(=($0, $4), =($2, $5))], joinType=[inner])
+ LogicalProject(C=[$0], C0=[$0], $f2=[+($0, 1)])
+ LogicalValues(tuples=[[{ 4 }]])
+ LogicalProject(N=[+($0, $1)], EXPR$0=[+($0, $1)], $f2=[$2])
+ LogicalJoin(condition=[=($0, $1)], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalProject(EXPR$0=[$1], $f2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 3 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject($f2=[+($0, 1)])
+ LogicalValues(tuples=[[{ 4 }]])
]]>
</Resource>
</TestCase>
@@ -4508,11 +4515,14 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2],
MGR=[$3], HIREDATE=[$4], SAL=[$
<Resource name="plan">
<![CDATA[
LogicalProject(C=[$0], D=[$1])
- LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])
+ LogicalJoin(condition=[=($0, $3)], joinType=[left])
LogicalValues(tuples=[[{ 4 }]])
- LogicalFilter(condition=[=($cor0.C, $1)])
- LogicalProject(C=[$cor0.C], EXPR$1=[*($0, $cor0.C)])
- LogicalValues(tuples=[[{ 2 }]])
+ LogicalFilter(condition=[=($2, $1)])
+ LogicalProject(C=[$1], EXPR$1=[*($0, $1)], C2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalValues(tuples=[[{ 4 }]])
]]>
</Resource>
</TestCase>
@@ -4525,11 +4535,14 @@ LogicalProject(C=[$0], D=[$1])
<Resource name="plan">
<![CDATA[
LogicalProject(C=[$0], D=[$1])
- LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])
+ LogicalJoin(condition=[=($0, $3)], joinType=[left])
LogicalValues(tuples=[[{ 4 }]])
- LogicalFilter(condition=[=($cor0.C, $1)])
- LogicalProject(C=[$cor0.C], EXPR$1=[*($0, $cor0.C)])
- LogicalValues(tuples=[[{ 2 }]])
+ LogicalFilter(condition=[=($2, $1)])
+ LogicalProject(C=[$1], EXPR$1=[*($0, $1)], C2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalValues(tuples=[[{ 4 }]])
]]>
</Resource>
</TestCase>
@@ -4543,11 +4556,14 @@ LogicalProject(C=[$0], D=[$1])
<Resource name="plan">
<![CDATA[
LogicalProject(C=[$0], D=[$1], C0=[$2])
- LogicalCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{0}])
+ LogicalJoin(condition=[=($0, $3)], joinType=[left])
LogicalValues(tuples=[[{ 4 }]])
- LogicalFilter(condition=[=($cor0.C, $1)])
- LogicalProject(C=[$cor0.C], EXPR$1=[*($0, $cor0.C)])
- LogicalValues(tuples=[[{ 2 }]])
+ LogicalFilter(condition=[=($2, $1)])
+ LogicalProject(C=[$1], EXPR$1=[*($0, $1)], C2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalValues(tuples=[[{ 4 }]])
]]>
</Resource>
</TestCase>
@@ -4560,14 +4576,16 @@ LogicalProject(C=[$0], D=[$1], C0=[$2])
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalProject(C=[$0], D=[$1], D0=[$2], C0=[$3])
- LogicalProject(C=[$0], D=[$1], C0=[$4], EXPR$1=[$5])
- LogicalCorrelate(correlation=[$cor0], joinType=[left],
requiredColumns=[{2, 3}])
- LogicalProject(C=[$0], D=[$1], $f2=[+($0, $1)], C0=[$0])
- LogicalValues(tuples=[[{ 4, 5 }]])
- LogicalFilter(condition=[=($cor0.$f2, $1)])
- LogicalProject(C=[$cor0.C], EXPR$1=[*($0, $cor0.C)])
- LogicalValues(tuples=[[{ 2 }]])
+LogicalProject(C=[$0], D=[$1], D0=[$4], C0=[$5])
+ LogicalJoin(condition=[AND(=($0, $6), =($2, $5))], joinType=[left])
+ LogicalProject(C=[$0], D=[$1], $f2=[+($0, $1)], C0=[$0])
+ LogicalValues(tuples=[[{ 4, 5 }]])
+ LogicalProject(C=[$1], EXPR$1=[*($0, $1)], C2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(C=[$0])
+ LogicalValues(tuples=[[{ 4, 5 }]])
]]>
</Resource>
</TestCase>
@@ -4583,17 +4601,19 @@ as r(n) on c=n]]>
</Resource>
<Resource name="plan">
<![CDATA[
-LogicalProject(C=[$0], N=[$1])
- LogicalProject(C=[$0], EXPR$0=[$3])
- LogicalCorrelate(correlation=[$cor0], joinType=[left],
requiredColumns=[{1, 2}])
- LogicalProject(C=[$0], C0=[$0], $f2=[+($0, 1)])
- LogicalValues(tuples=[[{ 4 }]])
- LogicalFilter(condition=[=($cor0.C, $0)])
- LogicalProject(EXPR$0=[+($0, $1)])
- LogicalJoin(condition=[=($0, $1)], joinType=[inner])
- LogicalValues(tuples=[[{ 2 }]])
- LogicalProject(EXPR$0=[$cor0.$f2])
- LogicalValues(tuples=[[{ 3 }]])
+LogicalProject(C=[$0], N=[$3])
+ LogicalJoin(condition=[AND(=($0, $3), =($2, $4))], joinType=[left])
+ LogicalProject(C=[$0], C0=[$0], $f2=[+($0, 1)])
+ LogicalValues(tuples=[[{ 4 }]])
+ LogicalProject(EXPR$0=[+($0, $1)], $f2=[$2])
+ LogicalJoin(condition=[=($0, $1)], joinType=[inner])
+ LogicalValues(tuples=[[{ 2 }]])
+ LogicalProject(EXPR$0=[$1], $f2=[$1])
+ LogicalJoin(condition=[true], joinType=[inner])
+ LogicalValues(tuples=[[{ 3 }]])
+ LogicalAggregate(group=[{0}])
+ LogicalProject($f2=[+($0, 1)])
+ LogicalValues(tuples=[[{ 4 }]])
]]>
</Resource>
</TestCase>
@@ -5235,11 +5255,16 @@ LogicalProject(D2=[$0], D3=[$1])
LogicalJoin(condition=[=($0, $1)], joinType=[left])
LogicalProject(D1=[+($0, 1)])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
- LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
- LogicalProject(D4=[$0], D6=[$2], $f0=[true])
- LogicalFilter(condition=[=($1, $0)])
- LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)], D6=[+($0,
6)])
+ LogicalProject(D4=[$0], D6=[$2], $f2=[$3])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(D1=[+($0, 1)])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
+ LogicalProject(D4=[$0], D6=[$2], $f0=[true])
+ LogicalFilter(condition=[=($1, $0)])
+ LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)],
D6=[+($0, 6)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -5265,11 +5290,16 @@ LogicalProject(D2=[$0], D3=[$1])
LogicalJoin(condition=[=($0, $1)], joinType=[left])
LogicalProject(D1=[+($0, 1)])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
- LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
- LogicalProject(D4=[$0], D6=[$2], $f0=[true])
- LogicalFilter(condition=[=($1, $0)])
- LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)], D6=[+($0,
6)])
+ LogicalProject(D4=[$0], D6=[$2], $f2=[$3])
+ LogicalJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ LogicalAggregate(group=[{0}])
+ LogicalProject(D1=[+($0, 1)])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
+ LogicalAggregate(group=[{0, 1}], agg#0=[MIN($2)])
+ LogicalProject(D4=[$0], D6=[$2], $f0=[true])
+ LogicalFilter(condition=[=($1, $0)])
+ LogicalProject(D4=[+($0, 4)], D5=[+($0, 5)],
D6=[+($0, 6)])
+ LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
]]>
</Resource>
</TestCase>
@@ -9697,15 +9727,13 @@ select * from t where exists (
<Resource name="plan">
<![CDATA[
LogicalProject(A=[$0], B=[$1])
- LogicalProject(EXPR$0=[$0], EXPR$1=[$1], $f0=[$2])
- LogicalFilter(condition=[IS NOT NULL($2)])
- LogicalCorrelate(correlation=[$cor0], joinType=[left],
requiredColumns=[{0}])
- LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
- LogicalValues(tuples=[[{ 1, 2 }]])
- LogicalAggregate(group=[{}], agg#0=[MIN($0)])
- LogicalProject($f0=[true])
- LogicalFilter(condition=[=($7, $cor0.A)])
- LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+ LogicalProject(EXPR$0=[$0], EXPR$1=[$1], DEPTNO=[CAST($2):INTEGER],
$f1=[CAST($3):BOOLEAN])
+ LogicalJoin(condition=[=($0, $2)], joinType=[inner])
+ LogicalProject(EXPR$0=[$0], EXPR$1=[$1])
+ LogicalValues(tuples=[[{ 1, 2 }]])
+ LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
+ LogicalProject(DEPTNO=[$7], $f0=[true])
+ LogicalTableScan(table=[[CATALOG, SALES, EMP]])
]]>
</Resource>
</TestCase>
diff --git a/core/src/test/resources/sql/blank.iq
b/core/src/test/resources/sql/blank.iq
index c8151c14f5..882d430412 100644
--- a/core/src/test/resources/sql/blank.iq
+++ b/core/src/test/resources/sql/blank.iq
@@ -92,13 +92,15 @@ select i, j from table1 where table1.j NOT IN (select i
from table2 where table1
EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0], expr#9=[=($t3, $t8)],
expr#10=[IS NULL($t1)], expr#11=[IS NOT NULL($t7)], expr#12=[<($t4, $t3)],
expr#13=[OR($t10, $t11, $t12)], expr#14=[IS NOT TRUE($t13)], expr#15=[OR($t9,
$t14)], proj#0..1=[{exprs}], $condition=[$t15])
EnumerableMergeJoin(condition=[AND(=($0, $6), =($1, $5))], joinType=[left])
EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
- EnumerableMergeJoin(condition=[=($0, $2)], joinType=[left])
- EnumerableSort(sort0=[$0], dir0=[ASC])
- EnumerableTableScan(table=[[BLANK, TABLE1]])
- EnumerableSort(sort0=[$0], dir0=[ASC])
- EnumerableAggregate(group=[{1}], c=[COUNT()], ck=[COUNT($0)])
- EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS NOT NULL($t1)],
proj#0..1=[{exprs}], $condition=[$t2])
- EnumerableTableScan(table=[[BLANK, TABLE2]])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $2)],
joinType=[left])
+ EnumerableTableScan(table=[[BLANK, TABLE1]])
+ EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NOT NULL($t2)],
expr#5=[0], expr#6=[CASE($t4, $t2, $t5)], expr#7=[IS NOT NULL($t3)],
expr#8=[CASE($t7, $t3, $t5)], J=[$t0], c=[$t6], ck=[$t8])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableAggregate(group=[{0}])
+ EnumerableTableScan(table=[[BLANK, TABLE1]])
+ EnumerableAggregate(group=[{1}], c=[COUNT()], ck=[COUNT($0)])
+ EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS NOT NULL($t1)],
proj#0..1=[{exprs}], $condition=[$t2])
+ EnumerableTableScan(table=[[BLANK, TABLE2]])
EnumerableSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[ASC])
EnumerableAggregate(group=[{0, 1}], i=[LITERAL_AGG(true)])
EnumerableCalc(expr#0..1=[{inputs}], expr#2=[IS NOT NULL($t1)],
expr#3=[IS NOT NULL($t0)], expr#4=[AND($t2, $t3)], proj#0..1=[{exprs}],
$condition=[$t4])
diff --git a/core/src/test/resources/sql/sub-query.iq
b/core/src/test/resources/sql/sub-query.iq
index 9feb458e53..cddd77cf4c 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -535,16 +535,24 @@ EnumerableCalc(expr#0..9=[{inputs}], expr#10=[0],
expr#11=[=($t5, $t10)], expr#1
EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
EnumerableTableScan(table=[[scott, DEPT]])
EnumerableSort(sort0=[$0], dir0=[ASC])
- EnumerableAggregate(group=[{3}], c=[COUNT()], ck=[COUNT($1)])
- EnumerableNestedLoopJoin(condition=[>($2, $3)], joinType=[inner])
- EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], JOB=[$t2],
DEPTNO=[$t7])
- EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NOT NULL($t2)],
expr#5=[0], expr#6=[CASE($t4, $t2, $t5)], expr#7=[IS NOT NULL($t3)],
expr#8=[CASE($t7, $t3, $t5)], DEPTNO0=[$t0], c=[$t6], ck=[$t8])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
EnumerableAggregate(group=[{1}])
EnumerableHashJoin(condition=[=($1, $2)], joinType=[semi])
EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0],
DEPTNO=[$t7])
EnumerableTableScan(table=[[scott, EMP]])
EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
EnumerableTableScan(table=[[scott, DEPT]])
+ EnumerableAggregate(group=[{3}], c=[COUNT()], ck=[COUNT($1)])
+ EnumerableNestedLoopJoin(condition=[>($2, $3)],
joinType=[inner])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], JOB=[$t2],
DEPTNO=[$t7])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableAggregate(group=[{1}])
+ EnumerableHashJoin(condition=[=($1, $2)], joinType=[semi])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0],
DEPTNO=[$t7])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+ EnumerableTableScan(table=[[scott, DEPT]])
EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
EnumerableCalc(expr#0..2=[{inputs}], expr#3=[IS NOT NULL($t0)],
proj#0..2=[{exprs}], $condition=[$t3])
EnumerableAggregate(group=[{1, 3}], i=[LITERAL_AGG(true)])
@@ -895,23 +903,19 @@ where sal + 100 not in (
# [CALCITE-356] AssertionError while translating query with WITH and
correlated sub-query
with t (a, b) as (select * from (values (1, 2)))
select * from t where exists (select 1 from "scott".emp where deptno = t.a);
-EnumerableCalc(expr#0..2=[{inputs}], proj#0..1=[{exprs}])
- EnumerableCorrelate(correlation=[$cor0], joinType=[inner],
requiredColumns=[{0}])
- EnumerableValues(tuples=[[{ 1, 2 }]])
- EnumerableAggregate(group=[{0}])
- EnumerableCalc(expr#0..7=[{inputs}], expr#8=[true],
expr#9=[CAST($t7):INTEGER], expr#10=[$cor0], expr#11=[$t10.A], expr#12=[=($t9,
$t11)], i=[$t8], $condition=[$t12])
- EnumerableTableScan(table=[[scott, EMP]])
+EnumerableCalc(expr#0=[{inputs}], expr#1=[1], expr#2=[2], A=[$t1], B=[$t2])
+ EnumerableAggregate(group=[{0}])
+ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t7):INTEGER],
expr#9=[1], expr#10=[=($t9, $t8)], DEPTNO0=[$t8], $condition=[$t10])
+ EnumerableTableScan(table=[[scott, EMP]])
!plan
# Similar query, identical plan
with t as (select * from (values (1, 2)) as t(a, b))
select * from t where exists (select 1 from "scott".emp where deptno = t.a);
-EnumerableCalc(expr#0..2=[{inputs}], proj#0..1=[{exprs}])
- EnumerableCorrelate(correlation=[$cor0], joinType=[inner],
requiredColumns=[{0}])
- EnumerableValues(tuples=[[{ 1, 2 }]])
- EnumerableAggregate(group=[{0}])
- EnumerableCalc(expr#0..7=[{inputs}], expr#8=[true],
expr#9=[CAST($t7):INTEGER], expr#10=[$cor0], expr#11=[$t10.A], expr#12=[=($t9,
$t11)], i=[$t8], $condition=[$t12])
- EnumerableTableScan(table=[[scott, EMP]])
+EnumerableCalc(expr#0=[{inputs}], expr#1=[1], expr#2=[2], A=[$t1], B=[$t2])
+ EnumerableAggregate(group=[{0}])
+ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t7):INTEGER],
expr#9=[1], expr#10=[=($t9, $t8)], DEPTNO0=[$t8], $condition=[$t10])
+ EnumerableTableScan(table=[[scott, EMP]])
!plan
# Uncorrelated
@@ -2624,13 +2628,16 @@ EnumerableAggregate(group=[{}], C=[COUNT()])
EnumerableMergeJoin(condition=[AND(=($3, $5), =($4, $6))], joinType=[left])
EnumerableSort(sort0=[$3], sort1=[$4], dir0=[ASC], dir1=[ASC])
EnumerableCalc(expr#0..6=[{inputs}], expr#7=[100], expr#8=[+($t2,
$t7)], expr#9=[CAST($t1):VARCHAR(14)], SAL=[$t2], c=[$t4], ck=[$t5], $f5=[$t8],
ENAME0=[$t9])
- EnumerableMergeJoin(condition=[=($3, $6)], joinType=[left])
- EnumerableSort(sort0=[$3], dir0=[ASC])
- EnumerableCalc(expr#0..7=[{inputs}],
expr#8=[CAST($t1):VARCHAR(14)], proj#0..1=[{exprs}], SAL=[$t5], ENAME0=[$t8])
- EnumerableTableScan(table=[[scott, EMP]])
- EnumerableSort(sort0=[$2], dir0=[ASC])
- EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1:BIGINT],
expr#4=[IS NOT NULL($t1)], c=[$t3], ck=[$t3], DNAME=[$t1], $condition=[$t4])
- EnumerableTableScan(table=[[scott, DEPT]])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($3, $6)],
joinType=[left])
+ EnumerableCalc(expr#0..7=[{inputs}],
expr#8=[CAST($t1):VARCHAR(14)], proj#0..1=[{exprs}], SAL=[$t5], ENAME0=[$t8])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..2=[{inputs}], expr#3=[IS NOT NULL($t2)],
expr#4=[0], expr#5=[CASE($t3, $t2, $t4)], c=[$t5], ck=[$t5], DNAME=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0,
$1)], joinType=[left])
+ EnumerableAggregate(group=[{0}])
+ EnumerableCalc(expr#0..7=[{inputs}],
expr#8=[CAST($t1):VARCHAR(14)], ENAME0=[$t8])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..2=[{inputs}], expr#3=[1:BIGINT],
expr#4=[IS NOT NULL($t1)], DNAME=[$t1], $f1=[$t3], $condition=[$t4])
+ EnumerableTableScan(table=[[scott, DEPT]])
EnumerableSort(sort0=[$0], sort1=[$1], dir0=[ASC], dir1=[ASC])
EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):DECIMAL(13, 2)
NOT NULL], expr#4=[true], expr#5=[IS NOT NULL($t1)], DEPTNO=[$t3], DNAME=[$t1],
i=[$t4], $condition=[$t5])
EnumerableTableScan(table=[[scott, DEPT]])
@@ -2640,12 +2647,16 @@ EnumerableAggregate(group=[{}], C=[COUNT()])
select empno from "scott".emp as e
where e.empno > ANY(
select 2 from "scott".dept e2 where e2.deptno = e.deptno) ;
-EnumerableCalc(expr#0..1=[{inputs}], EMPNO=[$t0])
- EnumerableHashJoin(condition=[AND(=($1, $6), >($0, $2))], joinType=[semi])
+EnumerableCalc(expr#0..6=[{inputs}], EMPNO=[$t5])
+ EnumerableNestedLoopJoin(condition=[AND(IS NOT DISTINCT FROM($6, $4),
OR(AND(>($5, $0), IS NOT TRUE(OR(IS NULL($3), =($1, 0)))), AND(>($5, $0), IS
NOT TRUE(OR(IS NULL($3), =($1, 0))), IS NOT TRUE(>($5, $0)), <=($1, $2))))],
joinType=[inner])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[IS NOT NULL($t3)],
expr#6=[0], expr#7=[CASE($t5, $t3, $t6)], m=[$t2], c=[$t7], d=[$t7],
trueLiteral=[$t4], DEPTNO=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableAggregate(group=[{7}])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[1:BIGINT],
expr#5=[true], DEPTNO=[$t0], EXPR$0=[$t3], $f2=[$t4], $f3=[$t5])
+ EnumerableTableScan(table=[[scott, DEPT]])
EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
EnumerableTableScan(table=[[scott, EMP]])
- EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[1:BIGINT],
expr#5=[true], m=[$t3], c=[$t4], d=[$t4], trueLiteral=[$t5], DEPTNO=[$t0])
- EnumerableTableScan(table=[[scott, DEPT]])
!plan
EMPNO
-------
@@ -2677,10 +2688,13 @@ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[>($t1,
$t2)], expr#8=[IS TRUE($t7)]
EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
EnumerableTableScan(table=[[scott, EMP]])
EnumerableSort(sort0=[$4], dir0=[ASC])
- EnumerableCalc(expr#0..3=[{inputs}], m=[$t1], c=[$t2], d=[$t2],
trueLiteral=[$t3], DEPTNO0=[$t0])
- EnumerableAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
- EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):SMALLINT NOT
NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
- EnumerableTableScan(table=[[scott, DEPT]])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[IS NOT NULL($t3)],
expr#6=[0], expr#7=[CASE($t5, $t3, $t6)], m=[$t2], c=[$t7], d=[$t7],
trueLiteral=[$t4], DEPTNO0=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableAggregate(group=[{0}], m=[MIN($1)], c=[COUNT()],
trueLiteral=[LITERAL_AGG(true)])
+ EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):SMALLINT
NOT NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
+ EnumerableTableScan(table=[[scott, DEPT]])
!plan
EMPNO | EXPR$1
-------+--------
@@ -2746,11 +2760,15 @@ select empno
from "scott".emp emp1
where empno <> some (select emp2.empno from "scott".emp emp2 where emp2.empno
= emp1.empno);
EnumerableCalc(expr#0..6=[{inputs}], expr#7=[<>($t2, $t1)], expr#8=[1],
expr#9=[<=($t3, $t8)], expr#10=[<>($t0, $t4)], expr#11=[IS NULL($t5)],
expr#12=[0], expr#13=[=($t1, $t12)], expr#14=[OR($t11, $t13)], expr#15=[IS NOT
TRUE($t14)], expr#16=[AND($t7, $t9, $t10, $t15)], expr#17=[=($t3, $t8)],
expr#18=[IS NOT NULL($t3)], expr#19=[AND($t7, $t18)], expr#20=[IS NOT
TRUE($t19)], expr#21=[AND($t17, $t10, $t15, $t20)], expr#22=[AND($t7, $t9)],
expr#23=[IS NOT TRUE($t22)], expr#24=[IS NOT TRUE( [...]
- EnumerableMergeJoin(condition=[=($0, $6)], joinType=[left])
+ EnumerableHashJoin(condition=[=($0, $6)], joinType=[left])
EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
EnumerableTableScan(table=[[scott, EMP]])
- EnumerableCalc(expr#0..7=[{inputs}], expr#8=[1:BIGINT], expr#9=[true],
c=[$t8], d=[$t8], dd=[$t8], m=[$t0], trueLiteral=[$t9], EMPNO1=[$t0])
- EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[IS NOT NULL($t2)],
expr#7=[0], expr#8=[CASE($t6, $t2, $t7)], expr#9=[IS NOT NULL($t3)],
expr#10=[CASE($t9, $t3, $t7)], c=[$t8], d=[$t8], dd=[$t10], m=[$t4],
trueLiteral=[$t5], EMPNO1=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[1:BIGINT], expr#9=[true],
EMPNO1=[$t0], $f1=[$t8], $f2=[$t8], EMPNO=[$t0], $f4=[$t9])
+ EnumerableTableScan(table=[[scott, EMP]])
!plan
+-------+
| EMPNO |
@@ -2790,16 +2808,18 @@ select *
from "scott".emp emp1
where empno <> some (select comm from "scott".emp where deptno = emp1.deptno);
EnumerableCalc(expr#0..13=[{inputs}], expr#14=[<>($t10, $t9)], expr#15=[1],
expr#16=[<=($t11, $t15)], expr#17=[AND($t14, $t16)], expr#18=[=($t11, $t15)],
expr#19=[OR($t17, $t18)], expr#20=[<>($t0, $t12)], expr#21=[IS NULL($t13)],
expr#22=[0], expr#23=[=($t9, $t22)], expr#24=[OR($t21, $t23)], expr#25=[IS NOT
TRUE($t24)], expr#26=[AND($t19, $t20, $t25)], expr#27=[IS NOT TRUE($t19)],
expr#28=[AND($t25, $t27)], expr#29=[OR($t26, $t28)], proj#0..7=[{exprs}],
$condition=[$t29])
- EnumerableMergeJoin(condition=[=($7, $8)], joinType=[left])
- EnumerableSort(sort0=[$7], dir0=[ASC])
- EnumerableTableScan(table=[[scott, EMP]])
- EnumerableSort(sort0=[$0], dir0=[ASC])
- EnumerableCalc(expr#0..5=[{inputs}], expr#6=[CAST($t1):BIGINT NOT NULL],
expr#7=[CAST($t2):BIGINT NOT NULL], expr#8=[CAST($t5):BOOLEAN NOT NULL],
DEPTNO=[$t0], c=[$t6], d=[$t7], dd=[$t3], m=[$t4], trueLiteral=[$t8])
- EnumerableAggregate(group=[{1}], c=[MIN($2) FILTER $7], d=[MIN($3)
FILTER $7], dd=[COUNT($0) FILTER $6], m=[MIN($4) FILTER $7],
trueLiteral=[MIN(true, $5) FILTER $7])
- EnumerableCalc(expr#0..6=[{inputs}], expr#7=[0], expr#8=[=($t6,
$t7)], expr#9=[2], expr#10=[=($t6, $t9)], proj#0..5=[{exprs}], $g_0=[$t8],
$g_2=[$t10])
- EnumerableAggregate(group=[{6, 7}], groups=[[{6, 7}, {7}]],
c=[COUNT()], d=[COUNT($6)], m=[MAX($6)], trueLiteral=[LITERAL_AGG(true)],
$g=[GROUPING($6, $7)])
- EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t7)],
proj#0..7=[{exprs}], $condition=[$t8])
- EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($7, $8)],
joinType=[left])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[IS NOT NULL($t2)],
expr#8=[0], expr#9=[CASE($t7, $t2, $t8)], expr#10=[IS NOT NULL($t3)],
expr#11=[CASE($t10, $t3, $t8)], expr#12=[IS NOT NULL($t4)], expr#13=[CASE($t12,
$t4, $t8)], DEPTNO=[$t0], c=[$t9], d=[$t11], dd=[$t13], m=[$t5],
trueLiteral=[$t6])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableAggregate(group=[{7}])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[CAST($t1):BIGINT NOT
NULL], expr#7=[CAST($t2):BIGINT NOT NULL], expr#8=[CAST($t5):BOOLEAN NOT NULL],
DEPTNO=[$t0], c=[$t6], d=[$t7], dd=[$t3], m=[$t4], trueLiteral=[$t8])
+ EnumerableAggregate(group=[{1}], c=[MIN($2) FILTER $7], d=[MIN($3)
FILTER $7], dd=[COUNT($0) FILTER $6], m=[MIN($4) FILTER $7],
trueLiteral=[MIN(true, $5) FILTER $7])
+ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[0], expr#8=[=($t6,
$t7)], expr#9=[2], expr#10=[=($t6, $t9)], proj#0..5=[{exprs}], $g_0=[$t8],
$g_2=[$t10])
+ EnumerableAggregate(group=[{6, 7}], groups=[[{6, 7}, {7}]],
c=[COUNT()], d=[COUNT($6)], m=[MAX($6)], trueLiteral=[LITERAL_AGG(true)],
$g=[GROUPING($6, $7)])
+ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT
NULL($t7)], proj#0..7=[{exprs}], $condition=[$t8])
+ EnumerableTableScan(table=[[scott, EMP]])
!plan
+-------+--------+----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
@@ -2848,12 +2868,16 @@ EnumerableCalc(expr#0..13=[{inputs}], expr#14=[<>($t9,
$t8)], expr#15=[1], expr#
EnumerableMergeJoin(condition=[=($0, $13)], joinType=[left])
EnumerableTableScan(table=[[scott, EMP]])
EnumerableSort(sort0=[$5], dir0=[ASC])
- EnumerableCalc(expr#0..4=[{inputs}], expr#5=[CAST($t1):BIGINT NOT NULL],
expr#6=[CAST($t3):INTEGER NOT NULL], expr#7=[CAST($t4):BOOLEAN NOT NULL],
c=[$t5], d=[$t5], dd=[$t2], m=[$t6], trueLiteral=[$t7], DEPTNO0=[$t0])
- EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $6], dd=[COUNT($1)
FILTER $5], m=[MIN($3) FILTER $6], trueLiteral=[MIN(true, $4) FILTER $6])
- EnumerableCalc(expr#0..5=[{inputs}], expr#6=[0], expr#7=[=($t5,
$t6)], expr#8=[1], expr#9=[=($t5, $t8)], proj#0..4=[{exprs}], $g_0=[$t7],
$g_1=[$t9])
- EnumerableAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}]],
c=[COUNT()], m=[MAX($1)], trueLiteral=[LITERAL_AGG(true)], $g=[GROUPING($0,
$1)])
- EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):SMALLINT
NOT NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
- EnumerableTableScan(table=[[scott, DEPT]])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[IS NOT NULL($t2)],
expr#7=[0], expr#8=[CASE($t6, $t2, $t7)], expr#9=[IS NOT NULL($t3)],
expr#10=[CASE($t9, $t3, $t7)], c=[$t8], d=[$t8], dd=[$t10], m=[$t4],
trueLiteral=[$t5], DEPTNO0=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[CAST($t1):BIGINT NOT
NULL], expr#6=[CAST($t3):INTEGER NOT NULL], expr#7=[CAST($t4):BOOLEAN NOT
NULL], DEPTNO0=[$t0], c=[$t5], dd=[$t2], m=[$t6], trueLiteral=[$t7])
+ EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $6],
dd=[COUNT($1) FILTER $5], m=[MIN($3) FILTER $6], trueLiteral=[MIN(true, $4)
FILTER $6])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[0], expr#7=[=($t5,
$t6)], expr#8=[1], expr#9=[=($t5, $t8)], proj#0..4=[{exprs}], $g_0=[$t7],
$g_1=[$t9])
+ EnumerableAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}]],
c=[COUNT()], m=[MAX($1)], trueLiteral=[LITERAL_AGG(true)], $g=[GROUPING($0,
$1)])
+ EnumerableCalc(expr#0..2=[{inputs}],
expr#3=[CAST($t0):SMALLINT NOT NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
+ EnumerableTableScan(table=[[scott, DEPT]])
!plan
+-------+-------+-----+-----+----------+-----+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
@@ -2896,12 +2920,16 @@ EnumerableCalc(expr#0..13=[{inputs}], expr#14=[<>($t9,
$t8)], expr#15=[1], expr#
EnumerableMergeJoin(condition=[=($0, $13)], joinType=[left])
EnumerableTableScan(table=[[scott, EMP]])
EnumerableSort(sort0=[$5], dir0=[ASC])
- EnumerableCalc(expr#0..4=[{inputs}], expr#5=[CAST($t1):BIGINT NOT NULL],
expr#6=[CAST($t3):INTEGER NOT NULL], expr#7=[CAST($t4):BOOLEAN NOT NULL],
c=[$t5], d=[$t5], dd=[$t2], m=[$t6], trueLiteral=[$t7], DEPTNO0=[$t0])
- EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $6], dd=[COUNT($1)
FILTER $5], m=[MIN($3) FILTER $6], trueLiteral=[MIN(true, $4) FILTER $6])
- EnumerableCalc(expr#0..5=[{inputs}], expr#6=[0], expr#7=[=($t5,
$t6)], expr#8=[1], expr#9=[=($t5, $t8)], proj#0..4=[{exprs}], $g_0=[$t7],
$g_1=[$t9])
- EnumerableAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}]],
c=[COUNT()], m=[MAX($1)], trueLiteral=[LITERAL_AGG(true)], $g=[GROUPING($0,
$1)])
- EnumerableCalc(expr#0..2=[{inputs}], expr#3=[CAST($t0):SMALLINT
NOT NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
- EnumerableTableScan(table=[[scott, DEPT]])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[IS NOT NULL($t2)],
expr#7=[0], expr#8=[CASE($t6, $t2, $t7)], expr#9=[IS NOT NULL($t3)],
expr#10=[CASE($t9, $t3, $t7)], c=[$t8], d=[$t8], dd=[$t10], m=[$t4],
trueLiteral=[$t5], DEPTNO0=[$t0])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..4=[{inputs}], expr#5=[CAST($t1):BIGINT NOT
NULL], expr#6=[CAST($t3):INTEGER NOT NULL], expr#7=[CAST($t4):BOOLEAN NOT
NULL], DEPTNO0=[$t0], c=[$t5], dd=[$t2], m=[$t6], trueLiteral=[$t7])
+ EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $6],
dd=[COUNT($1) FILTER $5], m=[MIN($3) FILTER $6], trueLiteral=[MIN(true, $4)
FILTER $6])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[0], expr#7=[=($t5,
$t6)], expr#8=[1], expr#9=[=($t5, $t8)], proj#0..4=[{exprs}], $g_0=[$t7],
$g_1=[$t9])
+ EnumerableAggregate(group=[{0, 1}], groups=[[{0, 1}, {0}]],
c=[COUNT()], m=[MAX($1)], trueLiteral=[LITERAL_AGG(true)], $g=[GROUPING($0,
$1)])
+ EnumerableCalc(expr#0..2=[{inputs}],
expr#3=[CAST($t0):SMALLINT NOT NULL], expr#4=[2], DEPTNO0=[$t3], EXPR$0=[$t4])
+ EnumerableTableScan(table=[[scott, DEPT]])
!plan
+-------+-------+-----+-----+----------+-----+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
@@ -2941,16 +2969,18 @@ select *
from "scott".emp emp1
where emp1.comm <> some (select comm from "scott".emp emp2 where emp2.sal =
emp1.sal);
EnumerableCalc(expr#0..13=[{inputs}], expr#14=[<>($t10, $t9)], expr#15=[1],
expr#16=[<=($t11, $t15)], expr#17=[AND($t14, $t16)], expr#18=[=($t11, $t15)],
expr#19=[OR($t17, $t18)], expr#20=[<>($t6, $t12)], expr#21=[IS NULL($t13)],
expr#22=[IS NULL($t6)], expr#23=[0], expr#24=[=($t9, $t23)], expr#25=[OR($t21,
$t22, $t24)], expr#26=[IS NOT TRUE($t25)], expr#27=[AND($t19, $t20, $t26)],
expr#28=[IS NOT TRUE($t19)], expr#29=[AND($t26, $t28)], expr#30=[OR($t27,
$t29)], proj#0..7=[{exprs}], $con [...]
- EnumerableMergeJoin(condition=[=($5, $8)], joinType=[left])
- EnumerableSort(sort0=[$5], dir0=[ASC])
- EnumerableTableScan(table=[[scott, EMP]])
- EnumerableSort(sort0=[$0], dir0=[ASC])
- EnumerableCalc(expr#0..5=[{inputs}], expr#6=[CAST($t1):BIGINT NOT NULL],
expr#7=[CAST($t2):BIGINT NOT NULL], expr#8=[CAST($t5):BOOLEAN NOT NULL],
SAL=[$t0], c=[$t6], d=[$t7], dd=[$t3], m=[$t4], trueLiteral=[$t8])
- EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $7], d=[MIN($3)
FILTER $7], dd=[COUNT($1) FILTER $6], m=[MIN($4) FILTER $7],
trueLiteral=[MIN(true, $5) FILTER $7])
- EnumerableCalc(expr#0..6=[{inputs}], expr#7=[0], expr#8=[=($t6,
$t7)], expr#9=[1], expr#10=[=($t6, $t9)], proj#0..5=[{exprs}], $g_0=[$t8],
$g_1=[$t10])
- EnumerableAggregate(group=[{5, 6}], groups=[[{5, 6}, {5}]],
c=[COUNT()], d=[COUNT($6)], m=[MAX($6)], trueLiteral=[LITERAL_AGG(true)],
$g=[GROUPING($5, $6)])
- EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t5)],
proj#0..7=[{exprs}], $condition=[$t8])
- EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($5, $8)],
joinType=[left])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[IS NOT NULL($t2)],
expr#8=[0], expr#9=[CASE($t7, $t2, $t8)], expr#10=[IS NOT NULL($t3)],
expr#11=[CASE($t10, $t3, $t8)], expr#12=[IS NOT NULL($t4)], expr#13=[CASE($t12,
$t4, $t8)], SAL=[$t0], c=[$t9], d=[$t11], dd=[$t13], m=[$t5], trueLiteral=[$t6])
+ EnumerableNestedLoopJoin(condition=[IS NOT DISTINCT FROM($0, $1)],
joinType=[left])
+ EnumerableAggregate(group=[{5}])
+ EnumerableTableScan(table=[[scott, EMP]])
+ EnumerableCalc(expr#0..5=[{inputs}], expr#6=[CAST($t1):BIGINT NOT
NULL], expr#7=[CAST($t2):BIGINT NOT NULL], expr#8=[CAST($t5):BOOLEAN NOT NULL],
SAL=[$t0], c=[$t6], d=[$t7], dd=[$t3], m=[$t4], trueLiteral=[$t8])
+ EnumerableAggregate(group=[{0}], c=[MIN($2) FILTER $7], d=[MIN($3)
FILTER $7], dd=[COUNT($1) FILTER $6], m=[MIN($4) FILTER $7],
trueLiteral=[MIN(true, $5) FILTER $7])
+ EnumerableCalc(expr#0..6=[{inputs}], expr#7=[0], expr#8=[=($t6,
$t7)], expr#9=[1], expr#10=[=($t6, $t9)], proj#0..5=[{exprs}], $g_0=[$t8],
$g_1=[$t10])
+ EnumerableAggregate(group=[{5, 6}], groups=[[{5, 6}, {5}]],
c=[COUNT()], d=[COUNT($6)], m=[MAX($6)], trueLiteral=[LITERAL_AGG(true)],
$g=[GROUPING($5, $6)])
+ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT
NULL($t5)], proj#0..7=[{exprs}], $condition=[$t8])
+ EnumerableTableScan(table=[[scott, EMP]])
!plan
+-------+--------+----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
@@ -4275,21 +4305,53 @@ FROM EMP i1 ORDER BY COMM;
| 300.00 | true |
| 500.00 | true |
| 1400.00 | true |
-| | |
-| | |
-| | |
-| | |
-| | |
-| | |
-| | |
-| | |
-| | |
-| | |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+| | false |
+---------+--------+
(14 rows)
!ok
+SELECT deptno
+FROM dept d
+WHERE 0 IN (
+ SELECT COUNT(*)
+ FROM emp e
+ WHERE d.deptno = e.deptno
+);
++--------+
+| DEPTNO |
++--------+
+| 40 |
++--------+
+(1 row)
+
+!ok
+
+SELECT deptno
+FROM dept d
+WHERE 'Regular' IN (
+ SELECT CASE WHEN SUM(sal) > 10 then 'VIP' else 'Regular' END expr
+ FROM emp e
+ WHERE d.deptno = e.deptno
+);
++--------+
+| DEPTNO |
++--------+
+| 40 |
++--------+
+(1 row)
+
+!ok
+
# Test case for [CALCITE-5789]
select deptno from dept d1 where exists (
select 1 from dept d2 where d2.deptno = d1.deptno and exists (