You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by ku...@apache.org on 2019/05/18 12:39:41 UTC
[flink] branch master updated: [FLINK-12519] [table-planner-blink]
Introduce transpose rules about semi/anti join
This is an automated email from the ASF dual-hosted git repository.
kurt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new 4fa3871 [FLINK-12519] [table-planner-blink] Introduce transpose rules about semi/anti join
4fa3871 is described below
commit 4fa387164cea44f8e0bac1aadab11433c0f0ff2b
Author: godfrey he <go...@163.com>
AuthorDate: Sat May 18 20:39:26 2019 +0800
[FLINK-12519] [table-planner-blink] Introduce transpose rules about semi/anti join
This closes #8450
---
.../FlinkSemiAntiJoinFilterTransposeRule.java | 91 ++
.../FlinkSemiAntiJoinJoinTransposeRule.java | 281 +++++
.../FlinkSemiAntiJoinProjectTransposeRule.java | 202 ++++
.../table/plan/rules/FlinkBatchRuleSets.scala | 9 +-
.../table/plan/rules/FlinkStreamRuleSets.scala | 9 +-
.../logical/ProjectSemiAntiJoinTransposeRule.scala | 167 +++
.../sql/join/BroadcastHashSemiAntiJoinTest.xml | 163 +--
.../batch/sql/join/NestedLoopSemiAntiJoinTest.xml | 280 ++---
.../table/plan/batch/sql/join/SemiAntiJoinTest.xml | 282 ++---
.../sql/join/ShuffledHashSemiAntiJoinTest.xml | 202 ++--
.../batch/sql/join/SortMergeSemiAntiJoinTest.xml | 202 ++--
.../FlinkSemiAntiJoinFilterTransposeRuleTest.xml | 79 ++
.../FlinkSemiAntiJoinJoinTransposeRuleTest.xml | 1135 ++++++++++++++++++++
.../FlinkSemiAntiJoinProjectTransposeRuleTest.xml | 97 ++
.../ProjectSemiAntiJoinTransposeRuleTest.xml | 463 ++++++++
.../plan/stream/sql/join/SemiAntiJoinTest.xml | 282 ++---
.../FlinkSemiAntiJoinFilterTransposeRuleTest.scala | 74 ++
.../FlinkSemiAntiJoinJoinTransposeRuleTest.scala | 357 ++++++
...FlinkSemiAntiJoinProjectTransposeRuleTest.scala | 79 ++
.../ProjectSemiAntiJoinTransposeRuleTest.scala | 149 +++
20 files changed, 3919 insertions(+), 684 deletions(-)
diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java
new file mode 100644
index 0000000..73c7036
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.tools.RelBuilderFactory;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ */
+
+/**
+ * Planner rule that pushes
+ * {@link org.apache.calcite.rel.core.SemiJoin}s down in a tree past
+ * a {@link org.apache.calcite.rel.core.Filter}.
+ *
+ * <p>The intention is to trigger other rules that will convert
+ * {@code SemiJoin}s.
+ *
+ * <p>SemiJoin(LogicalFilter(X), Y) → LogicalFilter(SemiJoin(X, Y))
+ *
+ * @see SemiJoinProjectTransposeRule
+ */
+public class FlinkSemiAntiJoinFilterTransposeRule extends RelOptRule {
+ public static final FlinkSemiAntiJoinFilterTransposeRule INSTANCE =
+ new FlinkSemiAntiJoinFilterTransposeRule(RelFactories.LOGICAL_BUILDER);
+
+ //~ Constructors -----------------------------------------------------------
+
+ /**
+ * Creates a FlinkSemiAntiJoinFilterTransposeRule.
+ */
+ public FlinkSemiAntiJoinFilterTransposeRule(RelBuilderFactory relBuilderFactory) {
+ super(operand(LogicalJoin.class,
+ some(operand(LogicalFilter.class, any()))),
+ relBuilderFactory, null);
+ }
+
+ //~ Methods ----------------------------------------------------------------
+
+ @Override
+ public boolean matches(RelOptRuleCall call) {
+ LogicalJoin join = call.rel(0);
+ return join.getJoinType() == JoinRelType.SEMI || join.getJoinType() == JoinRelType.ANTI;
+ }
+
+ // implement RelOptRule
+ public void onMatch(RelOptRuleCall call) {
+ LogicalJoin join = call.rel(0);
+ LogicalFilter filter = call.rel(1);
+
+ RelNode newJoin = LogicalJoin.create(
+ filter.getInput(),
+ join.getRight(),
+ join.getCondition(),
+ join.getVariablesSet(),
+ join.getJoinType());
+
+ final RelFactories.FilterFactory factory =
+ RelFactories.DEFAULT_FILTER_FACTORY;
+ RelNode newFilter =
+ factory.createFilter(newJoin, filter.getCondition());
+
+ call.transformTo(newFilter);
+ }
+}
+
+// End FlinkSemiAntiJoinFilterTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java
new file mode 100644
index 0000000..0bea511
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinJoinTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ * - Unsupported (NOT) EXISTS with uncorrelation.
+ * e.g. SELECT * FROM x, y WHERE x.c = y.f AND EXISTS (SELECT * FROM z)
+ * - Unsupported keys in SEMI/ANTI Join condition are from both Join's left and Join's right
+ * e.g. SELECT * FROM x, y WHERE x.c = y.f AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j)
+ */
+
+/**
+ * Planner rule that pushes a {@link org.apache.calcite.rel.core.SemiJoin}
+ * down in a tree past a {@link org.apache.calcite.rel.core.Join}
+ * in order to trigger other rules that will convert {@code SemiJoin}s.
+ *
+ * <ul>
+ * <li>SemiJoin(LogicalJoin(X, Y), Z) → LogicalJoin(SemiJoin(X, Z), Y)
+ * <li>SemiJoin(LogicalJoin(X, Y), Z) → LogicalJoin(X, SemiJoin(Y, Z))
+ * </ul>
+ *
+ * <p>Whether this
+ * first or second conversion is applied depends on which operands actually
+ * participate in the semi-join.</p>
+ */
+public class FlinkSemiAntiJoinJoinTransposeRule extends RelOptRule {
+ public static final FlinkSemiAntiJoinJoinTransposeRule INSTANCE =
+ new FlinkSemiAntiJoinJoinTransposeRule();
+
+ //~ Constructors -----------------------------------------------------------
+
+ /**
+ * Creates a FlinkSemiAntiJoinJoinTransposeRule.
+ */
+ private FlinkSemiAntiJoinJoinTransposeRule() {
+ super(operand(LogicalJoin.class,
+ some(operand(LogicalJoin.class, any()))));
+ }
+
+ //~ Methods ----------------------------------------------------------------
+
+ // implement RelOptRule
+ public void onMatch(RelOptRuleCall call) {
+ LogicalJoin semiAntiJoin = call.rel(0);
+ if (semiAntiJoin.getJoinType() != JoinRelType.SEMI &&
+ semiAntiJoin.getJoinType() != JoinRelType.ANTI) {
+ return;
+ }
+
+ final Join join = call.rel(1);
+ if (join.getJoinType() == JoinRelType.SEMI ||
+ join.getJoinType() == JoinRelType.ANTI) {
+ return;
+ }
+ // TODO support other join type
+ if (join.getJoinType() != JoinRelType.INNER) {
+ return;
+ }
+
+ // unsupported cases:
+ // 1. (NOT) EXISTS with uncorrelation
+ // 2. keys in SemiJoin condition are from both Join's left and Join's right
+
+ Pair<ImmutableBitSet, ImmutableBitSet> inputRefs = getSemiAntiJoinConditionInputRefs(semiAntiJoin);
+ final ImmutableBitSet leftInputRefs = inputRefs.left;
+ final ImmutableBitSet rightInputRefs = inputRefs.right;
+ // unsupported case1. (NOT) EXISTS with uncorrelation
+ // e.g. SELECT * FROM x, y WHERE x.c = y.f AND EXISTS (SELECT * FROM z)
+ // SemiJoin may be push to both Join's left and Join's right.
+ // TODO currently we does not handle this
+ if (leftInputRefs.isEmpty() || rightInputRefs.isEmpty()) {
+ return;
+ }
+
+ // X is the left child of the join below the semi-join
+ // Y is the right child of the join below the semi-join
+ // Z is the right child of the semi-join
+ int nFieldsX = join.getLeft().getRowType().getFieldList().size();
+ int nFieldsY = join.getRight().getRowType().getFieldList().size();
+ int nFieldsZ = semiAntiJoin.getRight().getRowType().getFieldList().size();
+ int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
+ List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>();
+
+ // create a list of fields for the full join result; note that
+ // we can't simply use the fields from the semi-join because the
+ // row-type of a semi-join only includes the left hand side fields
+ List<RelDataTypeField> joinFields =
+ semiAntiJoin.getRowType().getFieldList();
+ for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
+ fields.add(joinFields.get(i));
+ }
+ joinFields = semiAntiJoin.getRight().getRowType().getFieldList();
+ for (int i = 0; i < nFieldsZ; i++) {
+ fields.add(joinFields.get(i));
+ }
+
+ // determine which operands below the semi-join are the actual
+ // Rels that participate in the semi-join
+ int nKeysFromX = 0;
+ int nKeysFromY = 0;
+ for (int leftKey : leftInputRefs) {
+ if (leftKey < nFieldsX) {
+ nKeysFromX++;
+ } else {
+ nKeysFromY++;
+ }
+ }
+
+ // unsupported case2. keys in SemiJoin condition are from both Join's left and Join's right
+ // e.g. SELECT * FROM x, y WHERE x.c = y.f AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j)
+ if (nKeysFromX > 0 && nKeysFromY > 0) {
+ return;
+ }
+
+ // the keys must all originate from either the left or right;
+ // otherwise, a semi-join wouldn't have been created
+ assert (nKeysFromX == 0) || (nKeysFromX == leftInputRefs.cardinality());
+ assert (nKeysFromY == 0) || (nKeysFromY == leftInputRefs.cardinality());
+
+ // need to convert the semi/anti join condition and possibly the keys
+ RexNode newSemiAntiJoinFilter;
+ int[] adjustments = new int[nTotalFields];
+ if (nKeysFromX > 0) {
+ // (X, Y, Z) --> (X, Z, Y)
+ // semiJoin(X, Z)
+ // pass 0 as Y's adjustment because there shouldn't be any
+ // references to Y in the semi/anti join filter
+ setJoinAdjustments(
+ adjustments,
+ nFieldsX,
+ nFieldsY,
+ nFieldsZ,
+ 0,
+ -nFieldsY);
+ newSemiAntiJoinFilter =
+ semiAntiJoin.getCondition().accept(
+ new RelOptUtil.RexInputConverter(
+ semiAntiJoin.getCluster().getRexBuilder(),
+ fields,
+ adjustments));
+ } else {
+ // (X, Y, Z) --> (X, Y, Z)
+ // semiJoin(Y, Z)
+ setJoinAdjustments(
+ adjustments,
+ nFieldsX,
+ nFieldsY,
+ nFieldsZ,
+ -nFieldsX,
+ -nFieldsX);
+ newSemiAntiJoinFilter =
+ semiAntiJoin.getCondition().accept(
+ new RelOptUtil.RexInputConverter(
+ semiAntiJoin.getCluster().getRexBuilder(),
+ fields,
+ adjustments));
+ }
+
+ // create the new join
+ RelNode newSemiAntiJoinLeft;
+ if (nKeysFromX > 0) {
+ newSemiAntiJoinLeft = join.getLeft();
+ } else {
+ newSemiAntiJoinLeft = join.getRight();
+ }
+ Join newSemiAntiJoin = LogicalJoin.create(
+ newSemiAntiJoinLeft,
+ semiAntiJoin.getRight(),
+ newSemiAntiJoinFilter,
+ semiAntiJoin.getVariablesSet(),
+ semiAntiJoin.getJoinType());
+
+ RelNode leftJoinRel;
+ RelNode rightJoinRel;
+ if (nKeysFromX > 0) {
+ leftJoinRel = newSemiAntiJoin;
+ rightJoinRel = join.getRight();
+ } else {
+ leftJoinRel = join.getLeft();
+ rightJoinRel = newSemiAntiJoin;
+ }
+
+ RelNode newJoinRel =
+ join.copy(
+ join.getTraitSet(),
+ join.getCondition(),
+ leftJoinRel,
+ rightJoinRel,
+ join.getJoinType(),
+ join.isSemiJoinDone());
+
+ call.transformTo(newJoinRel);
+ }
+
+ /**
+ * Sets an array to reflect how much each index corresponding to a field
+ * needs to be adjusted. The array corresponds to fields in a 3-way join
+ * between (X, Y, and Z). X remains unchanged, but Y and Z need to be
+ * adjusted by some fixed amount as determined by the input.
+ *
+ * @param adjustments array to be filled out
+ * @param nFieldsX number of fields in X
+ * @param nFieldsY number of fields in Y
+ * @param nFieldsZ number of fields in Z
+ * @param adjustY the amount to adjust Y by
+ * @param adjustZ the amount to adjust Z by
+ */
+ private void setJoinAdjustments(
+ int[] adjustments,
+ int nFieldsX,
+ int nFieldsY,
+ int nFieldsZ,
+ int adjustY,
+ int adjustZ) {
+ for (int i = 0; i < nFieldsX; i++) {
+ adjustments[i] = 0;
+ }
+ for (int i = nFieldsX; i < (nFieldsX + nFieldsY); i++) {
+ adjustments[i] = adjustY;
+ }
+ for (int i = nFieldsX + nFieldsY; i < (nFieldsX + nFieldsY + nFieldsZ); i++) {
+ adjustments[i] = adjustZ;
+ }
+ }
+
+ private Pair<ImmutableBitSet, ImmutableBitSet> getSemiAntiJoinConditionInputRefs(Join semiAntiJoin) {
+ final int leftInputFieldCount = semiAntiJoin.getLeft().getRowType().getFieldCount();
+ final ImmutableBitSet.Builder leftInputBitSet = ImmutableBitSet.builder();
+ final ImmutableBitSet.Builder rightInputBitSet = ImmutableBitSet.builder();
+ semiAntiJoin.getCondition().accept(new RexVisitorImpl<Void>(true) {
+ public Void visitInputRef(RexInputRef inputRef) {
+ int index = inputRef.getIndex();
+ if (index < leftInputFieldCount) {
+ leftInputBitSet.set(index);
+ } else {
+ rightInputBitSet.set(index);
+ }
+ return null;
+ }
+ });
+ return new Pair<>(leftInputBitSet.build(), rightInputBitSet.build());
+ }
+}
+
+// End FlinkSemiAntiJoinJoinTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java
new file mode 100644
index 0000000..2a6611b
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.Pair;
+
+import java.util.List;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinProjectTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ * - Add predicate to check all expressions in Project should be RexInputRef
+ */
+
+/**
+ * Planner rule that pushes
+ * a {@link org.apache.calcite.rel.core.SemiJoin} down in a tree past
+ * a {@link org.apache.calcite.rel.core.Project}.
+ *
+ * <p>The intention is to trigger other rules that will convert
+ * {@code SemiJoin}s.
+ *
+ * <p>SemiJoin(LogicalProject(X), Y) → LogicalProject(SemiJoin(X, Y))
+ *
+ * @see org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule
+ */
+public class FlinkSemiAntiJoinProjectTransposeRule extends RelOptRule {
+
+ public static final FlinkSemiAntiJoinProjectTransposeRule INSTANCE =
+ new FlinkSemiAntiJoinProjectTransposeRule(RelFactories.LOGICAL_BUILDER);
+
+ //~ Constructors -----------------------------------------------------------
+
+ /**
+ * Creates a FlinkSemiAntiJoinProjectTransposeRule.
+ */
+ private FlinkSemiAntiJoinProjectTransposeRule(RelBuilderFactory relBuilderFactory) {
+ super(operand(LogicalJoin.class,
+ some(operand(LogicalProject.class, any()))),
+ relBuilderFactory, null);
+ }
+
+ @Override
+ public boolean matches(RelOptRuleCall call) {
+ LogicalJoin join = call.rel(0);
+ LogicalProject project = call.rel(1);
+
+ // only accept SEMI/ANTI join
+ JoinRelType joinType = join.getJoinType();
+ if (joinType != JoinRelType.SEMI && joinType != JoinRelType.ANTI) {
+ return false;
+ }
+ // all expressions in Project should be RexInputRef
+ for (RexNode p : project.getProjects()) {
+ if (!(p instanceof RexInputRef)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ //~ Methods ----------------------------------------------------------------
+
+ public void onMatch(RelOptRuleCall call) {
+ LogicalJoin join = call.rel(0);
+ LogicalProject project = call.rel(1);
+
+ // convert the semi/anti join condition to reflect the LHS with the project
+ // pulled up
+ RexNode newCondition = adjustCondition(project, join);
+ Join newJoin = LogicalJoin.create(
+ project.getInput(), join.getRight(), newCondition, join.getVariablesSet(), join.getJoinType());
+
+ // Create the new projection. Note that the projection expressions
+ // are the same as the original because they only reference the LHS
+ // of the semi/anti join and the semi/anti join only projects out the LHS
+ final RelBuilder relBuilder = call.builder();
+ relBuilder.push(newJoin);
+ relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
+
+ call.transformTo(relBuilder.build());
+ }
+
+ /**
+ * Pulls the project above the semi/anti join and returns the resulting semi/anti join
+ * condition. As a result, the semi/anti join condition should be modified such
+ * that references to the LHS of a semi/anti join should now reference the
+ * children of the project that's on the LHS.
+ *
+ * @param project LogicalProject on the LHS of the semi/anti join
+ * @param join the semi/anti join
+ * @return the modified semi/anti join condition
+ */
+ private RexNode adjustCondition(LogicalProject project, Join join) {
+ // create two RexPrograms -- the bottom one representing a
+ // concatenation of the project and the RHS of the semi/anti join and the
+ // top one representing the semi/anti join condition
+
+ RexBuilder rexBuilder = project.getCluster().getRexBuilder();
+ RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+ RelNode rightChild = join.getRight();
+
+ // for the bottom RexProgram, the input is a concatenation of the
+ // child of the project and the RHS of the semi/anti join
+ RelDataType bottomInputRowType =
+ SqlValidatorUtil.deriveJoinRowType(
+ project.getInput().getRowType(),
+ rightChild.getRowType(),
+ JoinRelType.INNER,
+ typeFactory,
+ null,
+ join.getSystemFieldList());
+ RexProgramBuilder bottomProgramBuilder =
+ new RexProgramBuilder(bottomInputRowType, rexBuilder);
+
+ // add the project expressions, then add input references for the RHS
+ // of the semi/anti join
+ for (Pair<RexNode, String> pair : project.getNamedProjects()) {
+ bottomProgramBuilder.addProject(pair.left, pair.right);
+ }
+ int nLeftFields = project.getInput().getRowType().getFieldCount();
+ List<RelDataTypeField> rightFields =
+ rightChild.getRowType().getFieldList();
+ int nRightFields = rightFields.size();
+ for (int i = 0; i < nRightFields; i++) {
+ final RelDataTypeField field = rightFields.get(i);
+ RexNode inputRef =
+ rexBuilder.makeInputRef(
+ field.getType(), i + nLeftFields);
+ bottomProgramBuilder.addProject(inputRef, field.getName());
+ }
+ RexProgram bottomProgram = bottomProgramBuilder.getProgram();
+
+ // input rowtype into the top program is the concatenation of the
+ // project and the RHS of the semi/anti join
+ RelDataType topInputRowType =
+ SqlValidatorUtil.deriveJoinRowType(
+ project.getRowType(),
+ rightChild.getRowType(),
+ JoinRelType.INNER,
+ typeFactory,
+ null,
+ join.getSystemFieldList());
+ RexProgramBuilder topProgramBuilder =
+ new RexProgramBuilder(
+ topInputRowType,
+ rexBuilder);
+ topProgramBuilder.addIdentity();
+ topProgramBuilder.addCondition(join.getCondition());
+ RexProgram topProgram = topProgramBuilder.getProgram();
+
+ // merge the programs and expand out the local references to form
+ // the new semi/anti join condition; it now references a concatenation of
+ // the project's child and the RHS of the semi/anti join
+ RexProgram mergedProgram =
+ RexProgramBuilder.mergePrograms(
+ topProgram,
+ bottomProgram,
+ rexBuilder);
+
+ return mergedProgram.expandLocalRef(
+ mergedProgram.getCondition());
+ }
+}
+
+// End FlinkSemiAntiJoinProjectTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
index bee709a..103b757 100644
--- a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
@@ -166,6 +166,8 @@ object FlinkBatchRuleSets {
// push all expressions to handle the time indicator correctly
new FlinkProjectJoinTransposeRule(
PushProjector.ExprCondition.FALSE, RelFactories.LOGICAL_BUILDER),
+ // push a projection to the children of a semi/anti Join
+ ProjectSemiAntiJoinTransposeRule.INSTANCE,
// merge projections
ProjectMergeRule.INSTANCE,
// remove identity project
@@ -233,7 +235,12 @@ object FlinkBatchRuleSets {
ProjectCalcMergeRule.INSTANCE,
FilterToCalcRule.INSTANCE,
ProjectToCalcRule.INSTANCE,
- FlinkCalcMergeRule.INSTANCE
+ FlinkCalcMergeRule.INSTANCE,
+
+ // semi/anti join transpose rule
+ FlinkSemiAntiJoinJoinTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinFilterTransposeRule.INSTANCE
)
/**
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
index fd8014b..9359ae1 100644
--- a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
@@ -168,6 +168,8 @@ object FlinkStreamRuleSets {
// push all expressions to handle the time indicator correctly
new FlinkProjectJoinTransposeRule(
PushProjector.ExprCondition.FALSE, RelFactories.LOGICAL_BUILDER),
+ // push a projection to the children of a semi/anti Join
+ ProjectSemiAntiJoinTransposeRule.INSTANCE,
// merge projections
ProjectMergeRule.INSTANCE,
// remove identity project
@@ -220,7 +222,12 @@ object FlinkStreamRuleSets {
ProjectCalcMergeRule.INSTANCE,
FilterToCalcRule.INSTANCE,
ProjectToCalcRule.INSTANCE,
- FlinkCalcMergeRule.INSTANCE
+ FlinkCalcMergeRule.INSTANCE,
+
+ // semi/anti join transpose rule
+ FlinkSemiAntiJoinJoinTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinFilterTransposeRule.INSTANCE
)
/**
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala
new file mode 100644
index 0000000..09ee0f6
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical
+
+import org.apache.calcite.plan.RelOptRule._
+import org.apache.calcite.plan.{RelOptRule, RelOptRuleCall, RelOptUtil}
+import org.apache.calcite.rel.RelNode
+import org.apache.calcite.rel.`type`.{RelDataType, RelDataTypeFactory}
+import org.apache.calcite.rel.core.{Join, JoinRelType, Project}
+import org.apache.calcite.rel.logical.{LogicalJoin, LogicalProject}
+import org.apache.calcite.rex.{RexInputRef, RexNode, RexShuttle}
+import org.apache.calcite.tools.RelBuilder
+import org.apache.calcite.util.ImmutableBitSet
+import org.apache.calcite.util.mapping.Mappings
+
+import java.util
+import java.util.function.IntFunction
+
+import scala.collection.JavaConversions._
+
+/**
+ * Planner rule that pushes a [[Project]] down in a tree past a semi/anti [[Join]]
+ * by splitting the projection into a projection on top of left child of the Join.
+ */
+class ProjectSemiAntiJoinTransposeRule
+ extends RelOptRule(
+ operand(classOf[LogicalProject],
+ operand(classOf[LogicalJoin], any)),
+ "ProjectSemiAntiJoinTransposeRule") {
+
+
+ override def matches(call: RelOptRuleCall): Boolean = {
+ val join: LogicalJoin = call.rel(1)
+ join.getJoinType match {
+ case JoinRelType.SEMI | JoinRelType.ANTI => true
+ case _ => false
+ }
+ }
+
+ override def onMatch(call: RelOptRuleCall): Unit = {
+ val project: LogicalProject = call.rel(0)
+ val join: LogicalJoin = call.rel(1)
+
+ // 1. calculate every inputs reference fields
+ val joinCondFields = RelOptUtil.InputFinder.bits(join.getCondition)
+ val projectFields = RelOptUtil.InputFinder.bits(project.getProjects, null)
+ val allNeededFields = if (projectFields.isEmpty) {
+ // if project does not reference any input fields, at least one field needs to be output
+ joinCondFields.union(ImmutableBitSet.of(0))
+ } else {
+ joinCondFields.union(projectFields)
+ }
+
+ val leftFieldCount = join.getLeft.getRowType.getFieldCount
+ val allInputFieldCount = leftFieldCount + join.getRight.getRowType.getFieldCount
+ if (allNeededFields.equals(ImmutableBitSet.range(0, allInputFieldCount))) {
+ return
+ }
+
+ val leftNeededFields = ImmutableBitSet.range(0, leftFieldCount).intersect(allNeededFields)
+ val rightNeededFields = ImmutableBitSet.range(leftFieldCount, allInputFieldCount)
+ .intersect(allNeededFields)
+
+ // 2. new join inputs
+ val newLeftInput = createNewJoinInput(call.builder, join.getLeft, leftNeededFields, 0)
+ val newRightInput = createNewJoinInput(
+ call.builder, join.getRight, rightNeededFields, leftFieldCount)
+
+ // mapping origin field index to new field index,
+ // used to rewrite join condition and top project
+ val mapping = Mappings.target(
+ new IntFunction[Integer]() {
+ def apply(i: Int): Integer = allNeededFields.indexOf(i)
+ },
+ allInputFieldCount, allNeededFields.cardinality())
+
+ // 3. create new join
+ val newJoin = createNewJoin(join, mapping, newLeftInput, newRightInput)
+
+ // 4. create top project
+ val newProjects = createNewProjects(project, newJoin, mapping)
+ val topProject = call.builder
+ .push(newJoin)
+ .project(newProjects, project.getRowType.getFieldNames)
+ .build
+
+ call.transformTo(topProject)
+ }
+
+ private def createNewJoinInput(
+ relBuilder: RelBuilder,
+ originInput: RelNode,
+ inputNeededFields: ImmutableBitSet,
+ offset: Int): RelNode = {
+ val rexBuilder = originInput.getCluster.getRexBuilder
+ val typeBuilder = new RelDataTypeFactory.FieldInfoBuilder(relBuilder.getTypeFactory)
+ val newProjects: util.List[RexNode] = new util.ArrayList[RexNode]()
+ val newFieldNames: util.List[String] = new util.ArrayList[String]()
+ inputNeededFields.toList.foreach { i =>
+ newProjects.add(rexBuilder.makeInputRef(originInput, i - offset))
+ newFieldNames.add(originInput.getRowType.getFieldNames.get(i - offset))
+ typeBuilder.add(originInput.getRowType.getFieldList.get(i - offset))
+ }
+ relBuilder.push(originInput).project(newProjects, newFieldNames).build
+ }
+
+ private def createNewJoin(
+ originJoin: Join,
+ mapping: Mappings.TargetMapping,
+ newLeftInput: RelNode,
+ newRightInput: RelNode): Join = {
+ val newCondition = rewriteJoinCondition(originJoin, mapping)
+ LogicalJoin.create(newLeftInput, newRightInput, newCondition, originJoin.getVariablesSet,
+ originJoin.getJoinType)
+ }
+
+ private def rewriteJoinCondition(
+ originJoin: Join,
+ mapping: Mappings.TargetMapping): RexNode = {
+ val rexBuilder = originJoin.getCluster.getRexBuilder
+ val rexShuttle = new RexShuttle() {
+ override def visitInputRef(ref: RexInputRef): RexNode = {
+ val leftFieldCount = originJoin.getLeft.getRowType.getFieldCount
+ val fieldType: RelDataType = if (ref.getIndex < leftFieldCount) {
+ originJoin.getLeft.getRowType.getFieldList.get(ref.getIndex).getType
+ } else {
+ originJoin.getRight.getRowType.getFieldList.get(ref.getIndex - leftFieldCount).getType
+ }
+ rexBuilder.makeInputRef(fieldType, mapping.getTarget(ref.getIndex))
+ }
+ }
+ originJoin.getCondition.accept(rexShuttle)
+ }
+
+ private def createNewProjects(
+ originProject: Project,
+ newInput: RelNode,
+ mapping: Mappings.TargetMapping): Seq[RexNode] = {
+ val rexBuilder = originProject.getCluster.getRexBuilder
+ val projectShuffle = new RexShuttle() {
+ override def visitInputRef(ref: RexInputRef): RexNode = {
+ rexBuilder.makeInputRef(newInput, mapping.getTarget(ref.getIndex))
+ }
+ }
+ originProject.getProjects.map(_.accept(projectShuffle))
+ }
+}
+
+object ProjectSemiAntiJoinTransposeRule {
+ val INSTANCE = new ProjectSemiAntiJoinTransposeRule
+}
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
index 9d9cd80..789b29d 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
@@ -177,8 +177,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -218,9 +218,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
+- Exchange(distribution=[single])
+- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
- :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -307,23 +308,23 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -469,8 +470,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], isBroadcast=[true], build=[right])
- :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], isBroadcast=[true], build=[right])
+ :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -595,8 +596,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], isBroadcast=[true], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], isBroadcast=[true], build=[right])
+ :- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d, k])
+- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], isBroadcast=[true], build=[left])
@@ -705,13 +707,12 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], isBroadcast=[true], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -770,9 +771,10 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], isBroadcast=[true], build=[right])
- :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], isBroadcast=[true], build=[right])
+ :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -891,8 +893,9 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], isBroadcast=[true], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], isBroadcast=[true], build=[right])
+ :- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[EXPR$0])
+- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1002,9 +1005,10 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], isBroadcast=[true], build=[right])
- :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], isBroadcast=[true], build=[right])
+ :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1043,8 +1047,9 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
Calc(select=[b])
+- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
:- Calc(select=[b])
- : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], isBroadcast=[true], build=[right])
+ : :- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1079,8 +1084,8 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], isBroadcast=[true], build=[right])
- :- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], isBroadcast=[true], build=[right])
+ :- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1281,8 +1286,9 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], isBroadcast=[true], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], isBroadcast=[true], build=[right])
+ :- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1316,16 +1322,16 @@ LogicalTableScan(table=[[t, source: [TestTableSource(i, j, k)]]])
HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1395,19 +1401,19 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[right])
-:- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[right])
-: :- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[left])
-: : :- Exchange(distribution=[broadcast])
-: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
-: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[broadcast])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[broadcast])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[left])
+:- Exchange(distribution=[broadcast])
+: +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], isBroadcast=[true], build=[right])
+: :- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], isBroadcast=[true], build=[right])
+: : :- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
+: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+: : +- Exchange(distribution=[broadcast])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[broadcast])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -1564,8 +1570,9 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d])
- +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], isBroadcast=[true], build=[right])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], isBroadcast=[true], build=[right])
+ :- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1657,8 +1664,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1804,8 +1811,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], isBroadcast=[true], build=[right])
- :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], isBroadcast=[true], build=[right])
+ :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1837,8 +1844,8 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], isBroadcast=[true], build=[right])
- :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], isBroadcast=[true], build=[right])
+ :- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], isBroadcast=[true], build=[right])
: :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
: : :- Calc(select=[a, b, c, c0, ck, i0])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
index c967fb6..09a0420 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
@@ -147,14 +147,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- LocalHashAggregate(select=[])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- LocalHashAggregate(select=[])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -228,8 +227,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -260,22 +259,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
- :- Exchange(distribution=[single])
- : +- Calc(select=[e])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[single])
- +- Calc(select=[j], where=[>(i, 10)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+ :- Exchange(distribution=[single])
+ : +- Calc(select=[e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[single])
+ +- Calc(select=[j], where=[>(i, 10)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -307,9 +306,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
+- Exchange(distribution=[single])
+- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
- :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -396,23 +396,23 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -614,8 +614,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
- :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
+ :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -670,8 +670,8 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3], build=[right])
+ :- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
: +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
: :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
: : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
@@ -786,8 +786,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
+ :- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d, k])
+- NestedLoopJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -896,13 +897,12 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -961,9 +961,10 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
- :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
+ :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1082,8 +1083,9 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
+ :- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[EXPR$0])
+- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1194,11 +1196,12 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
- : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
- : : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3], build=[right])
+ :- Calc(select=[b, CASE(AND(<>(c, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i], build=[right])
+ : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c], build=[right], singleRowJoin=[true])
+ : : :- Calc(select=[a, b])
+ : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : +- Exchange(distribution=[broadcast])
: : +- Calc(select=[c])
: : +- HashAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
@@ -1241,9 +1244,10 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
- :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
+ :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1282,8 +1286,9 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
Calc(select=[b])
+- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
:- Calc(select=[b])
- : +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
+ : :- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1318,8 +1323,8 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[right])
- :- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[right])
+ :- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1355,8 +1360,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
+ :- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d])
+- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1558,8 +1564,9 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
+ :- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1628,16 +1635,16 @@ LogicalTableScan(table=[[t, source: [TestTableSource(i, j, k)]]])
NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1839,8 +1846,9 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
+ :- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1868,19 +1876,19 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
-:- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-: :- NestedLoopJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-: : :- Exchange(distribution=[broadcast])
-: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
-: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[broadcast])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[broadcast])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+NestedLoopJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
+:- Exchange(distribution=[broadcast])
+: +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+: :- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+: : :- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
+: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+: : +- Exchange(distribution=[broadcast])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[broadcast])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -1954,8 +1962,9 @@ NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f], build=[right])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e], build=[right])
+ :- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[j, i])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2002,14 +2011,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- LocalHashAggregate(select=[])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- LocalHashAggregate(select=[])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2053,8 +2061,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2200,8 +2208,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
- :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
+ :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2233,8 +2241,8 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
+ :- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
: :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
: : :- Calc(select=[a, b, c, c0, ck, i0])
@@ -2340,13 +2348,12 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2473,14 +2480,15 @@ LogicalProject(e=[$1], d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i], build=[right])
- : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
- : : :- Calc(select=[a, b, c, c0, ck, i0])
- : : : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0], build=[right])
- : : : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck], build=[right], singleRowJoin=[true])
- : : : : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3], build=[right])
+ :- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c, 0), AND(<>(c, 0), IS NULL(i), >=(ck0, c), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i], build=[right])
+ : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0], build=[right], singleRowJoin=[true])
+ : : :- Calc(select=[a, b, c AS c0, ck, i0])
+ : : : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0], build=[right])
+ : : : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, ck], build=[right], singleRowJoin=[true])
+ : : : : :- Calc(select=[a, b])
+ : : : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : : : +- Exchange(distribution=[broadcast])
: : : : +- SortAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
: : : : +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
index 2a962ba..e8efee0 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
@@ -149,14 +149,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- LocalHashAggregate(select=[])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- LocalHashAggregate(select=[])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -232,8 +231,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -264,22 +263,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
- :- Exchange(distribution=[hash[e]])
- : +- Calc(select=[e])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[hash[j]])
- +- Calc(select=[j], where=[>(i, 10)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+ :- Exchange(distribution=[hash[e]])
+ : +- Calc(select=[e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[hash[j]])
+ +- Calc(select=[j], where=[>(i, 10)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -311,9 +310,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
+- Exchange(distribution=[single])
+- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
- :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -400,23 +400,23 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -626,9 +626,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
:- Exchange(distribution=[hash[$f3, $f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0, e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -684,9 +684,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3], build=[left])
:- Exchange(distribution=[hash[$f3, c]])
- : +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+ : +- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
: +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
: :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
: : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
@@ -805,9 +805,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
:- Exchange(distribution=[hash[a, c]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d, k]])
+- Calc(select=[d, k])
+- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -919,14 +920,13 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
- :- Exchange(distribution=[hash[a]])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Exchange(distribution=[hash[a]])
+: +- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -986,10 +986,11 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
:- Exchange(distribution=[hash[EXPR$0, c]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1112,9 +1113,10 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0]])
+- Calc(select=[EXPR$0])
+- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1228,12 +1230,13 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3], build=[left])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
- : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
- : : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[b, CASE(AND(<>(c, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i], build=[right])
+ : :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c], build=[right], singleRowJoin=[true])
+ : : :- Calc(select=[a, b])
+ : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : +- Exchange(distribution=[broadcast])
: : +- Calc(select=[c])
: : +- HashAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
@@ -1276,10 +1279,11 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
:- Exchange(distribution=[hash[EXPR$0]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1318,9 +1322,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
Calc(select=[b])
+- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
:- Calc(select=[b])
- : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+ : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
: :- Exchange(distribution=[hash[a]])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[hash[d]])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1355,9 +1360,9 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[left])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+ : +- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1393,9 +1398,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
:- Exchange(distribution=[hash[a]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
+- HashJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1602,9 +1608,10 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1674,16 +1681,16 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
:- Exchange(distribution=[hash[a]])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1895,9 +1902,10 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
- +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
+ +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
:- Exchange(distribution=[hash[e]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[j]])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1925,22 +1933,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
:- Exchange(distribution=[hash[a]])
-: +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-: :- Exchange(distribution=[hash[b]])
-: : +- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-: : :- Exchange(distribution=[hash[a]])
+: +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+: :- Exchange(distribution=[hash[a]])
+: : +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+: : :- Exchange(distribution=[hash[b]])
: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- Exchange(distribution=[hash[d]])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[hash[j]])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+: : +- Exchange(distribution=[hash[j]])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[hash[i]])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2015,9 +2023,10 @@ NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d
:- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[d])
- +- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f], build=[right])
+ +- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e], build=[left])
:- Exchange(distribution=[hash[d]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[i]])
+- Calc(select=[j, i])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2064,14 +2073,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- LocalHashAggregate(select=[])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- LocalHashAggregate(select=[])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2116,8 +2124,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2266,9 +2274,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
:- Exchange(distribution=[hash[$f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2300,9 +2308,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
:- Exchange(distribution=[hash[c]])
- : +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
: :- Exchange(distribution=[hash[a]])
: : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
@@ -2411,13 +2419,12 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2546,16 +2553,17 @@ LogicalProject(e=[$1], d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3], build=[right])
- :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
- : +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i], build=[right])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3], build=[right])
+ :- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c, 0), AND(<>(c, 0), IS NULL(i), >=(ck0, c), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i], build=[right])
: :- Exchange(distribution=[hash[a]])
- : : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
- : : :- Calc(select=[a, b, c, c0, ck, i0])
- : : : +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0], build=[right])
+ : : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0], build=[right], singleRowJoin=[true])
+ : : :- Calc(select=[a, b, c AS c0, ck, i0])
+ : : : +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0], build=[right])
: : : :- Exchange(distribution=[hash[a]])
- : : : : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck], build=[right], singleRowJoin=[true])
- : : : : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : : : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, ck], build=[right], singleRowJoin=[true])
+ : : : : :- Calc(select=[a, b])
+ : : : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : : : +- Exchange(distribution=[broadcast])
: : : : +- SortAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
: : : : +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
index c5ac381..bd57fc8 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
@@ -154,8 +154,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -186,22 +186,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
- :- Exchange(distribution=[hash[e]])
- : +- Calc(select=[e])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[hash[j]])
- +- Calc(select=[j], where=[>(i, 10)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+ :- Exchange(distribution=[hash[e]])
+ : +- Calc(select=[e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[hash[j]])
+ +- Calc(select=[j], where=[>(i, 10)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -233,9 +233,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
+- Exchange(distribution=[single])
+- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
- :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -322,23 +323,23 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -490,9 +491,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
:- Exchange(distribution=[hash[$f3, $f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0, e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -622,9 +623,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
:- Exchange(distribution=[hash[a, c]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d, k]])
+- Calc(select=[d, k])
+- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -708,14 +710,13 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
- :- Exchange(distribution=[hash[a]])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Exchange(distribution=[hash[a]])
+: +- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -775,10 +776,11 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
:- Exchange(distribution=[hash[EXPR$0, c]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -901,9 +903,10 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0]])
+- Calc(select=[EXPR$0])
+- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1016,10 +1019,11 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
:- Exchange(distribution=[hash[EXPR$0]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1058,9 +1062,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
Calc(select=[b])
+- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
:- Calc(select=[b])
- : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+ : +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
: :- Exchange(distribution=[hash[a]])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[hash[d]])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1095,9 +1100,9 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[left])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+ : +- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1133,9 +1138,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
:- Exchange(distribution=[hash[a]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
+- HashJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1315,9 +1321,10 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1352,16 +1359,16 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
:- Exchange(distribution=[hash[a]])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1432,22 +1439,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
:- Exchange(distribution=[hash[a]])
-: +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-: :- Exchange(distribution=[hash[b]])
-: : +- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-: : :- Exchange(distribution=[hash[a]])
+: +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+: :- Exchange(distribution=[hash[a]])
+: : +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+: : :- Exchange(distribution=[hash[b]])
: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- Exchange(distribution=[hash[d]])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[hash[j]])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+: : +- Exchange(distribution=[hash[j]])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[hash[i]])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -1613,9 +1620,10 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
- +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
+ +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
:- Exchange(distribution=[hash[e]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[j]])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1709,8 +1717,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1859,9 +1867,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
:- Exchange(distribution=[hash[$f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1893,9 +1901,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
:- Exchange(distribution=[hash[c]])
- : +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
: :- Exchange(distribution=[hash[a]])
: : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
index 2495488..cba2428 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
@@ -182,8 +182,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -214,22 +214,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
- :- Exchange(distribution=[hash[e]])
- : +- Calc(select=[e])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[hash[j]])
- +- Calc(select=[j], where=[>(i, 10)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
+ :- Exchange(distribution=[hash[e]])
+ : +- Calc(select=[e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[hash[j]])
+ +- Calc(select=[j], where=[>(i, 10)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -261,9 +261,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
+- Exchange(distribution=[single])
+- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+- Calc(select=[true AS i])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
- :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -350,23 +351,23 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -518,9 +519,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4])
:- Exchange(distribution=[hash[$f3, $f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0, e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -650,9 +651,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c])
:- Exchange(distribution=[hash[a, c]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d, k]])
+- Calc(select=[d, k])
+- SortMergeJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k])
@@ -765,14 +767,13 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3])
- :- Exchange(distribution=[hash[a]])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+:- Exchange(distribution=[hash[a]])
+: +- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -832,10 +833,11 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0])
:- Exchange(distribution=[hash[EXPR$0, c]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -958,9 +960,10 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0]])
+- Calc(select=[EXPR$0])
+- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1073,10 +1076,11 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0])
:- Exchange(distribution=[hash[EXPR$0]])
- : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
- : :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+ : :- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[broadcast])
: +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1115,9 +1119,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
Calc(select=[b])
+- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
:- Calc(select=[b])
- : +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+ : +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b])
: :- Exchange(distribution=[hash[a]])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[hash[d]])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1152,9 +1157,9 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+ : +- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1190,9 +1195,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c])
:- Exchange(distribution=[hash[a]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
+- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0])
@@ -1400,9 +1406,10 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1437,16 +1444,16 @@ SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
:- Exchange(distribution=[hash[a]])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
- :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[broadcast])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
- +- Exchange(distribution=[single])
- +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+ :- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[broadcast])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+ +- Exchange(distribution=[single])
+ +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1517,22 +1524,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-SortMergeJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f])
+SortMergeJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
:- Exchange(distribution=[hash[a]])
-: +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f])
-: :- Exchange(distribution=[hash[b]])
-: : +- SortMergeJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
-: : :- Exchange(distribution=[hash[a]])
+: +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c])
+: :- Exchange(distribution=[hash[a]])
+: : +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c])
+: : :- Exchange(distribution=[hash[b]])
: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- Exchange(distribution=[hash[d]])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[hash[j]])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+: : +- Exchange(distribution=[hash[j]])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[hash[i]])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -1698,9 +1705,10 @@ SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
- +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f])
+ +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e])
:- Exchange(distribution=[hash[e]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[j]])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1794,8 +1802,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
- :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+ :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[broadcast])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1944,9 +1952,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4])
++- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4])
:- Exchange(distribution=[hash[$f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1978,9 +1986,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3])
++- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3])
:- Exchange(distribution=[hash[c]])
- : +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- SortMergeJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i])
: :- Exchange(distribution=[hash[a]])
: : +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml
new file mode 100644
index 0000000..de2084b
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" ?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<Root>
+ <TestCase name="testAntiJoinFilterTranspose">
+ <Resource name="sql">
+ <![CDATA[
+SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+ WHERE b NOT IN (SELECT e FROM MyTable2)
+ ]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[NOT(IN($1, {
+LogicalProject(e=[$1])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2])
+ +- LogicalFilter(condition=[>($0, 10)])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[>($0, 10)])
+ +- LogicalJoin(condition=[OR(=($1, $3), IS NULL($1), IS NULL($3))], joinType=[anti])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(e=[$1])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testSemiJoinFilterTranspose">
+ <Resource name="sql">
+ <![CDATA[
+SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+ WHERE b IN (SELECT e FROM MyTable2)
+ ]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[IN($1, {
+LogicalProject(e=[$1])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2])
+ +- LogicalFilter(condition=[>($0, 10)])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[>($0, 10)])
+ +- LogicalJoin(condition=[=($1, $3)], joinType=[semi])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(e=[$1])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml
new file mode 100644
index 0000000..6bece3e
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml
@@ -0,0 +1,1135 @@
+<?xml version="1.0" ?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<Root>
+ <TestCase name="testEXISTS_EquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[$6], joinType=[semi])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject($f0=[IS NOT NULL($0)])
+ +- LogicalAggregate(group=[{}], m=[MIN($0)])
+ +- LogicalProject(i=[true])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testEXISTS_EquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.a), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[=($3, $0)], joinType=[semi])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testEXISTS_EquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.d), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[=($3, $0)], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testEXISTS_NonEquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(>($0, $cor0.a), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[>($3, $0)], joinType=[semi])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testEXISTS_NonEquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(<($0, $cor0.d), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[<($3, $0)], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin4">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0], j=[$1])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin5">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND (x.a, y.e) IN (SELECT z.i, z.j FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, $4, {
+LogicalProject(i=[$0], j=[$1])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(=($0, $6), =($4, $7))], joinType=[semi])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_EquiCondition_InnerJoin6">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(=($0, $6), =($4, $7))], joinType=[semi])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_FullJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_FullJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_LeftJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_LeftJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_NonEquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[AND(=($0, $3), >($1, $4))], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_NonEquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[AND(=($0, $3), >($1, $4))], joinType=[semi])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0], j=[$1])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_NonEquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(=($0, $6), >($4, $7))], joinType=[semi])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_NonEquiCondition_InnerJoin4">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(=($3, $6), >($1, $7))], joinType=[semi])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_RightJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testIN_RightJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+ +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+ :- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[$6], joinType=[anti])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject($f0=[IS NOT NULL($0)])
+ +- LogicalAggregate(group=[{}], m=[MIN($0)])
+ +- LogicalProject(i=[true])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.a), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[=($3, $0)], joinType=[anti])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.d), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[=($3, $0)], joinType=[anti])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_EXISTS_NonEquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(>($0, $cor0.a), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[>($3, $0)], joinType=[anti])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_EXISTS_NonEquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(<($0, $cor0.d), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[<($3, $0)], joinType=[anti])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin4">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0], j=[$1])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin5">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND (x.a, y.e) NOT IN (SELECT z.i, z.j FROM z WHERE z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, $4, {
+LogicalProject(i=[$0], j=[$1])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), OR(=($4, $7), IS NULL($4), IS NULL($7)))], joinType=[anti])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_EquiCondition_InnerJoin6">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), =($4, $7))], joinType=[anti])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin1">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), >($1, $4))], joinType=[anti])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin2">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), >($1, $4))], joinType=[anti])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalProject(i=[$0], j=[$1])
+ : +- LogicalFilter(condition=[<($1, 50)])
+ : +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), >($4, $7))], joinType=[anti])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin4">
+ <Resource name="sql">
+ <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+ +- LogicalJoin(condition=[AND(OR(=($3, $6), IS NULL($3), IS NULL($6)), >($1, $7))], joinType=[anti])
+ :- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0], j=[$1])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml
new file mode 100644
index 0000000..b9d53b4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" ?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<Root>
+ <TestCase name="testCannotTranspose">
+ <Resource name="sql">
+ <![CDATA[
+SELECT a, f FROM
+ (SELECT a * 2 as a, b, d + 1 as d, e, f FROM x, y WHERE x.c = y.f) xy
+WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+ ]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[AND(>($3, 100), IN($2, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[*($0, 2)], b=[$1], d=[+($3, 1)], e=[$4], f=[$5])
+ +- LogicalFilter(condition=[=($2, $5)])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[>($3, 100)])
+ +- LogicalJoin(condition=[=($2, $5)], joinType=[semi])
+ :- LogicalProject(a=[*($0, 2)], b=[$1], d=[+($3, 1)], e=[$4], f=[$5])
+ : +- LogicalFilter(condition=[=($2, $5)])
+ : +- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTranspose">
+ <Resource name="sql">
+ <![CDATA[
+SELECT a, f FROM
+ (SELECT a, b, d, e, f FROM x, y WHERE x.c = y.f) xy
+WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+ ]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[AND(>($3, 100), IN($2, {
+LogicalProject(i=[$0])
+ LogicalFilter(condition=[<($1, 50)])
+ LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], d=[$3], e=[$4], f=[$5])
+ +- LogicalFilter(condition=[=($2, $5)])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[>($3, 100)])
+ +- LogicalProject(a=[$0], b=[$1], d=[$3], e=[$4], f=[$5])
+ +- LogicalFilter(condition=[=($2, $5)])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+ +- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+ :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(i=[$0])
+ +- LogicalFilter(condition=[<($1, 50)])
+ +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml
new file mode 100644
index 0000000..68d6996
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml
@@ -0,0 +1,463 @@
+<?xml version="1.0" ?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<Root>
+ <TestCase name="testNotNeedTransposeProject_Anti1">
+ <Resource name="sql">
+ <![CDATA[SELECT * FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNotNeedTransposeProject_Anti2">
+ <Resource name="sql">
+ <![CDATA[SELECT b + 1, c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNotNeedTransposeProject_Anti3">
+ <Resource name="sql">
+ <![CDATA[SELECT c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2 WHERE b = e)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalFilter(condition=[=($cor0.b, $1)])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))], variablesSet=[[$cor0]])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(c=[$2])
++- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0], e=[$1])
+ +- LogicalFilter(condition=[true])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNotNeedTransposeProject_Semi1">
+ <Resource name="sql">
+ <![CDATA[SELECT * FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNotNeedTransposeProject_Semi2">
+ <Resource name="sql">
+ <![CDATA[SELECT b + 1, c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testNotNeedTransposeProject_Semi3">
+ <Resource name="sql">
+ <![CDATA[SELECT c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2 WHERE b = e)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalFilter(condition=[=($cor0.b, $1)])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})], variablesSet=[[$cor0]])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(c=[$2])
++- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0], e=[$1])
+ +- LogicalFilter(condition=[true])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Anti1">
+ <Resource name="sql">
+ <![CDATA[SELECT a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalJoin(condition=[OR(=($0, $1), IS NULL($0), IS NULL($1))], joinType=[anti])
+:- LogicalProject(a=[$0])
+: +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Anti2">
+ <Resource name="sql">
+ <![CDATA[SELECT a + 1 FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalJoin(condition=[OR(=($0, $1), IS NULL($0), IS NULL($1))], joinType=[anti])
+ :- LogicalProject(a=[$0])
+ : +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Anti3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, b FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+:- LogicalProject(a=[$0], b=[$1])
+: +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Anti4">
+ <Resource name="sql">
+ <![CDATA[SELECT b, a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+ :- LogicalProject(a=[$0], b=[$1])
+ : +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Anti5">
+ <Resource name="sql">
+ <![CDATA[SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(d=[$3])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(d=[$1])
++- LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+ :- LogicalProject(a=[$0], d=[$3])
+ : +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+ : +- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_EmptyProject">
+ <Resource name="sql">
+ <![CDATA[SELECT * FROM MyTable1 WHERE EXISTS (SELECT * FROM MyTable2, LATERAL TABLE(table_func(f)) AS T(f1) WHERE EXISTS (SELECT * FROM MyTable3))]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[EXISTS({
+LogicalFilter(condition=[EXISTS({
+LogicalTableScan(table=[[MyTable3, source: [TestTableSource(i, j, k)]]])
+})])
+ LogicalCorrelate(correlation=[$cor0], joinType=[inner], requiredColumns=[{2}])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+ LogicalTableFunctionScan(invocation=[table_func($cor0.f)], rowType=[RecordType(VARCHAR(65536) f0)], elementType=[class [Ljava.lang.Object;])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[$3], joinType=[semi])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject($f0=[IS NOT NULL($0)])
+ +- LogicalAggregate(group=[{}], m=[MIN($0)])
+ +- LogicalProject(i=[true])
+ +- LogicalJoin(condition=[$1], joinType=[semi])
+ :- LogicalProject(d=[$0])
+ : +- LogicalCorrelate(correlation=[$cor0], joinType=[inner], requiredColumns=[{2}])
+ : :- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+ : +- LogicalTableFunctionScan(invocation=[table_func($cor0.f)], rowType=[RecordType(VARCHAR(65536) f0)], elementType=[class [Ljava.lang.Object;])
+ +- LogicalProject($f0=[IS NOT NULL($0)])
+ +- LogicalAggregate(group=[{}], m=[MIN($0)])
+ +- LogicalProject(i=[true])
+ +- LogicalTableScan(table=[[MyTable3, source: [TestTableSource(i, j, k)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Semi1">
+ <Resource name="sql">
+ <![CDATA[SELECT a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalJoin(condition=[=($0, $1)], joinType=[semi])
+:- LogicalProject(a=[$0])
+: +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Semi2">
+ <Resource name="sql">
+ <![CDATA[SELECT a + 1 FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalJoin(condition=[=($0, $1)], joinType=[semi])
+ :- LogicalProject(a=[$0])
+ : +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Semi3">
+ <Resource name="sql">
+ <![CDATA[SELECT a, b FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(a=[$0], b=[$1])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+:- LogicalProject(a=[$0], b=[$1])
+: +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Semi4">
+ <Resource name="sql">
+ <![CDATA[SELECT b, a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+ :- LogicalProject(a=[$0], b=[$1])
+ : +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testTransposeProject_Semi5">
+ <Resource name="sql">
+ <![CDATA[SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t WHERE a IN (SELECT d FROM MyTable2)]]>
+ </Resource>
+ <Resource name="planBefore">
+ <![CDATA[
+LogicalProject(d=[$3])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+ LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+ +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+ +- LogicalJoin(condition=[true], joinType=[inner])
+ :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ <Resource name="planAfter">
+ <![CDATA[
+LogicalProject(d=[$1])
++- LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+ :- LogicalProject(a=[$0], d=[$3])
+ : +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+ : +- LogicalJoin(condition=[true], joinType=[inner])
+ : :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+ : +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+ +- LogicalProject(d=[$0])
+ +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+ </Resource>
+ </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
index 6534b5a..55657c9 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
@@ -150,14 +150,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3])
- :- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[single])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftSemiJoin], where=[true], select=[a, b, c])
+:- Exchange(distribution=[single])
+: +- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -232,9 +231,9 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, c])
:- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
+ : +- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[single])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -264,22 +263,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
- :- Exchange(distribution=[single])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[single])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- GroupAggregate(select=[MIN(i) AS m])
- +- Exchange(distribution=[single])
- +- Calc(select=[true AS i])
- +- Join(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
- :- Exchange(distribution=[hash[e]])
- : +- Calc(select=[e])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[hash[j]])
- +- Calc(select=[j], where=[>(i, 10)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+Join(joinType=[LeftSemiJoin], where=[$f0], select=[c])
+:- Exchange(distribution=[single])
+: +- Calc(select=[c])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- GroupAggregate(select=[MIN(i) AS m])
+ +- Exchange(distribution=[single])
+ +- Calc(select=[true AS i])
+ +- Join(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
+ :- Exchange(distribution=[hash[e]])
+ : +- Calc(select=[e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[hash[j]])
+ +- Calc(select=[j], where=[>(i, 10)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -311,10 +310,11 @@ Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
+- GroupAggregate(select=[MIN(i) AS m])
+- Exchange(distribution=[single])
+- Calc(select=[true AS i])
- +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0])
+ +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d])
:- Exchange(distribution=[single])
- : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d])
+ : +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[single])
+- Calc(select=[IS NOT NULL(m) AS $f0])
+- GroupAggregate(select=[MIN(i) AS m])
@@ -400,22 +400,22 @@ LogicalUnion(all=[false])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
- :- Exchange(distribution=[single])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[single])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- GroupAggregate(select=[MIN(i) AS m])
- +- Exchange(distribution=[single])
- +- Calc(select=[true AS i])
- +- GroupAggregate(groupBy=[e, f], select=[e, f])
- +- Exchange(distribution=[hash[e, f]])
- +- Union(all=[true], union=[e, f])
- :- Calc(select=[e, f], where=[>(d, 10)])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Calc(select=[j, k], where=[<(i, 100)])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+Join(joinType=[LeftSemiJoin], where=[$f0], select=[a])
+:- Exchange(distribution=[single])
+: +- Calc(select=[a])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- GroupAggregate(select=[MIN(i) AS m])
+ +- Exchange(distribution=[single])
+ +- Calc(select=[true AS i])
+ +- GroupAggregate(groupBy=[e, f], select=[e, f])
+ +- Exchange(distribution=[hash[e, f]])
+ +- Union(all=[true], union=[e, f])
+ :- Calc(select=[e, f], where=[>(d, 10)])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Calc(select=[j, k], where=[<(i, 100)])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -623,9 +623,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4])
++- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4])
:- Exchange(distribution=[hash[$f3, $f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0, e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -681,9 +681,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3])
++- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3])
:- Exchange(distribution=[hash[$f3, c]])
- : +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+ : +- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
: +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i])
: :- Exchange(distribution=[single])
: : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0])
@@ -802,9 +802,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c])
:- Exchange(distribution=[hash[a, c]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d, k]])
+- Calc(select=[d, k])
+- Join(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k])
@@ -917,14 +918,13 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3])
- :- Exchange(distribution=[hash[a]])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+:- Exchange(distribution=[hash[a]])
+: +- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -983,11 +983,12 @@ LogicalProject(i=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0])
++- Join(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0])
:- Exchange(distribution=[hash[EXPR$0, c]])
- : +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0])
+ : +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0])
: :- Exchange(distribution=[single])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a, c])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[single])
: +- GroupAggregate(select=[MAX(d) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1108,9 +1109,10 @@ LogicalProject(EXPR$0=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[EXPR$0]])
+- Calc(select=[EXPR$0])
+- GroupAggregate(groupBy=[f], select=[f, MAX(e) AS EXPR$0])
@@ -1222,14 +1224,15 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- Join(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3])
++- Join(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
- : +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i])
+ : +- Calc(select=[b, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+ : +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i])
: :- Exchange(distribution=[single])
- : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0])
+ : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c])
: : :- Exchange(distribution=[single])
- : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : : +- Calc(select=[a, b])
+ : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : +- Exchange(distribution=[single])
: : +- Calc(select=[c])
: : +- GroupAggregate(select=[COUNT(*) AS c, COUNT(EXPR$0) AS ck])
@@ -1270,11 +1273,12 @@ LogicalProject(j=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0])
++- Join(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0])
:- Exchange(distribution=[hash[EXPR$0]])
- : +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0])
+ : +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0])
: :- Exchange(distribution=[single])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[single])
: +- GroupAggregate(select=[MAX(e) AS EXPR$0])
: +- Exchange(distribution=[single])
@@ -1313,9 +1317,10 @@ Calc(select=[b])
+- Join(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0])
:- Exchange(distribution=[single])
: +- Calc(select=[b])
- : +- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+ : +- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b])
: :- Exchange(distribution=[hash[a]])
- : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : +- Calc(select=[a, b])
+ : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: +- Exchange(distribution=[hash[d]])
: +- Calc(select=[d], where=[>(e, 10)])
: +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1349,9 +1354,9 @@ LogicalProject(e=[$1])
<Resource name="planAfter">
<![CDATA[
Calc(select=[s])
-+- Join(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3])
++- Join(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3])
:- Exchange(distribution=[hash[$f3]])
- : +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+ : +- Calc(select=[s, $f3], where=[>($f2, 2)])
: +- GroupAggregate(groupBy=[b], select=[b, SUM(a) AS s, COUNT(*) AS $f2, MAX(b) AS $f3])
: +- Exchange(distribution=[hash[b]])
: +- Calc(select=[b, a])
@@ -1386,9 +1391,10 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c])
:- Exchange(distribution=[hash[a]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, c])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
+- Join(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0])
@@ -1594,9 +1600,10 @@ LogicalUnion(all=[false])
<Resource name="planAfter">
<![CDATA[
Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b])
:- Exchange(distribution=[hash[b]])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : +- Calc(select=[a, b])
+ : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- GroupAggregate(groupBy=[e], select=[e])
+- Exchange(distribution=[hash[e]])
@@ -1666,16 +1673,16 @@ Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
:- Exchange(distribution=[hash[a]])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
- +- Calc(select=[d])
- +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f])
- :- Exchange(distribution=[single])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
- +- Exchange(distribution=[single])
- +- Calc(select=[IS NOT NULL(m) AS $f0])
- +- GroupAggregate(select=[MIN(i) AS m])
- +- Exchange(distribution=[single])
- +- Calc(select=[true AS i])
- +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+ +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d])
+ :- Exchange(distribution=[single])
+ : +- Calc(select=[d])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ +- Exchange(distribution=[single])
+ +- Calc(select=[IS NOT NULL(m) AS $f0])
+ +- GroupAggregate(select=[MIN(i) AS m])
+ +- Exchange(distribution=[single])
+ +- Calc(select=[true AS i])
+ +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
]]>
</Resource>
</TestCase>
@@ -1887,9 +1894,10 @@ Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[d]])
+- Calc(select=[d])
- +- Join(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f])
+ +- Join(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e])
:- Exchange(distribution=[hash[e]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[j]])
+- Calc(select=[j])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1917,22 +1925,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Join(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f])
+Join(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
:- Exchange(distribution=[hash[a]])
-: +- Join(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f])
-: :- Exchange(distribution=[hash[b]])
-: : +- Join(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
-: : :- Exchange(distribution=[hash[a]])
+: +- Join(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c])
+: :- Exchange(distribution=[hash[a]])
+: : +- Join(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c])
+: : :- Exchange(distribution=[hash[b]])
: : : +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
: : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-: : +- Exchange(distribution=[hash[d]])
-: : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-: +- Exchange(distribution=[hash[j]])
-: +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-: +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
- +- Calc(select=[i], where=[<(j, 100)])
- +- Reused(reference_id=[1])
+: : +- Exchange(distribution=[hash[j]])
+: : +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+: : +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+: +- Exchange(distribution=[hash[i]])
+: +- Calc(select=[i], where=[<(j, 100)])
+: +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2008,9 +2016,10 @@ Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], selec
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[single])
+- Calc(select=[d])
- +- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f])
+ +- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e])
:- Exchange(distribution=[hash[d]])
- : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+ : +- Calc(select=[d, e])
+ : +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+- Exchange(distribution=[hash[i]])
+- Calc(select=[j, i])
+- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2058,14 +2067,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3])
- :- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[single])
- +- Calc(select=[])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftAntiJoin], where=[true], select=[a, b, c])
+:- Exchange(distribution=[single])
+: +- Calc(select=[a, b, c], where=[<(a, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+ +- Calc(select=[])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2110,9 +2118,9 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, c])
:- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
+ : +- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[single])
+- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2230,9 +2238,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
<Resource name="planAfter">
<![CDATA[
Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4])
:- Exchange(distribution=[hash[$f4]])
- : +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+ : +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+- Exchange(distribution=[hash[e]])
+- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2264,9 +2272,9 @@ LogicalProject(d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3])
:- Exchange(distribution=[hash[c]])
- : +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
: +- Join(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i])
: :- Exchange(distribution=[hash[a]])
: : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0])
@@ -2372,14 +2380,13 @@ LogicalProject(d=[$0])
</Resource>
<Resource name="planAfter">
<![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3])
- :- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
- : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
- +- Exchange(distribution=[single])
- +- Calc(select=[d])
- +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c])
+:- Exchange(distribution=[single])
+: +- Calc(select=[a, b, c], where=[>(b, 10)])
+: +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+ +- Calc(select=[d])
+ +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
]]>
</Resource>
</TestCase>
@@ -2510,19 +2517,20 @@ LogicalProject(e=[$1], d=[$0])
<Resource name="planAfter">
<![CDATA[
Calc(select=[b])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3])
:- Exchange(distribution=[single])
- : +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
- : +- Join(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i])
+ : +- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+ : +- Join(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i])
: :- Exchange(distribution=[hash[a]])
- : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0])
+ : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0])
: : :- Exchange(distribution=[single])
- : : : +- Calc(select=[a, b, c, c0, ck, i0])
- : : : +- Join(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0])
+ : : : +- Calc(select=[a, b, c0, ck, i0])
+ : : : +- Join(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0])
: : : :- Exchange(distribution=[hash[a]])
- : : : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck])
+ : : : : +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, ck])
: : : : :- Exchange(distribution=[single])
- : : : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+ : : : : : +- Calc(select=[a, b])
+ : : : : : +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
: : : : +- Exchange(distribution=[single])
: : : : +- GroupAggregate(select=[COUNT(*) AS c, COUNT(i) AS ck])
: : : : +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala
new file mode 100644
index 0000000..74e97d4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+ * Test for [[FlinkSemiAntiJoinFilterTransposeRule]].
+ */
+class FlinkSemiAntiJoinFilterTransposeRuleTest extends TableTestBase {
+
+ private val util = batchTestUtil()
+
+ @Before
+ def setup(): Unit = {
+ util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+ util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+ "rules",
+ FlinkHepRuleSetProgramBuilder.newBuilder
+ .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_SEQUENCE)
+ .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .add(RuleSets.ofList(
+ FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinFilterTransposeRule.INSTANCE))
+ .build()
+ )
+
+ util.addTableSource[(Int, Long, String)]("MyTable1", 'a, 'b, 'c)
+ util.addTableSource[(Int, Long, String)]("MyTable2", 'd, 'e, 'f)
+ }
+
+ @Test
+ def testSemiJoinFilterTranspose(): Unit = {
+ val sqlQuery =
+ """
+ |SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+ | WHERE b IN (SELECT e FROM MyTable2)
+ """.stripMargin
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testAntiJoinFilterTranspose(): Unit = {
+ val sqlQuery =
+ """
+ |SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+ | WHERE b NOT IN (SELECT e FROM MyTable2)
+ """.stripMargin
+ util.verifyPlan(sqlQuery)
+ }
+
+}
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala
new file mode 100644
index 0000000..67af5d4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala
@@ -0,0 +1,357 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+ * Test for [[FlinkSemiAntiJoinJoinTransposeRule]].
+ */
+class FlinkSemiAntiJoinJoinTransposeRuleTest extends TableTestBase {
+
+ private val util = batchTestUtil()
+
+ @Before
+ def setup(): Unit = {
+ util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+ util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+ "rules",
+ FlinkHepRuleSetProgramBuilder.newBuilder
+ .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_COLLECTION)
+ .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .add(RuleSets.ofList(
+ FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinFilterTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinJoinTransposeRule.INSTANCE))
+ .build()
+ )
+
+ util.addTableSource[(Int, Long, String)]("x", 'a, 'b, 'c)
+ util.addTableSource[(Int, Long, String)]("y", 'd, 'e, 'f)
+ util.addTableSource[(Int, Long, String)]("z", 'i, 'j, 'k)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin2(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin4(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin5(): Unit = {
+ // keys of semi-join are from both join's right and join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "(x.a, y.e) IN (SELECT z.i, z.j FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_EquiCondition_InnerJoin6(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_NonEquiCondition_InnerJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_NonEquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_NonEquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from both join's right and join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_NonEquiCondition_InnerJoin4(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testEXISTS_EquiCondition_InnerJoin1(): Unit = {
+ // no keys
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "EXISTS (SELECT * FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testEXISTS_EquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testEXISTS_EquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+
+ // keys of semi-join are from both join's right and join's left
+ // calcite does not support below sql:
+ // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ // "EXISTS (SELECT * FROM z WHERE z.i = y.d AND x.b = z.j AND z.j < 50)"
+ }
+
+ @Test
+ def testEXISTS_NonEquiCondition_InnerJoin1(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testEXISTS_NonEquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+
+ // keys of semi-join are from both join's right and join's left
+ // calcite does not support below sql:
+ // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ // "EXISTS (SELECT * FROM z WHERE z.i < y.d AND x.b = z.j AND z.j < 50)"
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin1(): Unit = {
+ // keys of anti-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d NOT IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin2(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a NOT IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin4(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a NOT IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin5(): Unit = {
+ // keys of semi-join are from both join's right and join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "(x.a, y.e) NOT IN (SELECT z.i, z.j FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_EquiCondition_InnerJoin6(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_NonEquiCondition_InnerJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_NonEquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_NonEquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from both join's right and join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "x.a NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_IN_NonEquiCondition_InnerJoin4(): Unit = {
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "y.d NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_EXISTS_EquiCondition_InnerJoin1(): Unit = {
+ // no keys
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "NOT EXISTS (SELECT * FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_EXISTS_EquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "NOT EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_EXISTS_EquiCondition_InnerJoin3(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+
+ // keys of semi-join are from both join's right and join's left
+ // calcite does not support below sql:
+ // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ // "NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND x.b = z.j AND z.j < 50)"
+ }
+
+ @Test
+ def testNOT_EXISTS_NonEquiCondition_InnerJoin1(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "NOT EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testNOT_EXISTS_NonEquiCondition_InnerJoin2(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ "NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)"
+ util.verifyPlan(sqlQuery)
+
+ // keys of semi-join are from both join's right and join's left
+ // calcite does not support below sql:
+ // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+ // "NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND x.b = z.j AND z.j < 50)"
+ }
+
+ @Test
+ def testIN_LeftJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_LeftJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_RightJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_RightJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_FullJoin1(): Unit = {
+ // keys of semi-join are from join's right
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testIN_FullJoin2(): Unit = {
+ // keys of semi-join are from join's left
+ val sqlQuery = "SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy " +
+ "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+ util.verifyPlan(sqlQuery)
+ }
+
+}
+
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala
new file mode 100644
index 0000000..1b65184
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+ * Test for [[FlinkSemiAntiJoinProjectTransposeRule]].
+ */
+class FlinkSemiAntiJoinProjectTransposeRuleTest extends TableTestBase {
+
+ private val util = batchTestUtil()
+
+ @Before
+ def setup(): Unit = {
+ util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+ util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+ "rules",
+ FlinkHepRuleSetProgramBuilder.newBuilder
+ .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_COLLECTION)
+ .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .add(RuleSets.ofList(
+ FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinFilterTransposeRule.INSTANCE,
+ FlinkSemiAntiJoinJoinTransposeRule.INSTANCE))
+ .build()
+ )
+
+ util.addTableSource[(Int, Long, String)]("x", 'a, 'b, 'c)
+ util.addTableSource[(Int, Long, String)]("y", 'd, 'e, 'f)
+ util.addTableSource[(Int, Long, String)]("z", 'i, 'j, 'k)
+ }
+
+ @Test
+ def testTranspose(): Unit = {
+ val sqlQuery =
+ """
+ |SELECT a, f FROM
+ | (SELECT a, b, d, e, f FROM x, y WHERE x.c = y.f) xy
+ |WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+ """.stripMargin
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testCannotTranspose(): Unit = {
+ val sqlQuery =
+ """
+ |SELECT a, f FROM
+ | (SELECT a * 2 as a, b, d + 1 as d, e, f FROM x, y WHERE x.c = y.f) xy
+ |WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+ """.stripMargin
+ util.verifyPlan(sqlQuery)
+ }
+
+}
+
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala
new file mode 100644
index 0000000..00ae40d
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.runtime.utils.JavaUserDefinedTableFunctions.StringSplit
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+ * Test for [[ProjectSemiAntiJoinTransposeRule]].
+ */
+class ProjectSemiAntiJoinTransposeRuleTest extends TableTestBase {
+
+ private val util = batchTestUtil()
+
+ @Before
+ def setup(): Unit = {
+ util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+ util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+ "rules",
+ FlinkHepRuleSetProgramBuilder.newBuilder
+ .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_SEQUENCE)
+ .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+ .add(RuleSets.ofList(ProjectSemiAntiJoinTransposeRule.INSTANCE))
+ .build()
+ )
+
+ util.addTableSource[(Int, Long, String)]("MyTable1", 'a, 'b, 'c)
+ util.addTableSource[(Int, Long, String)]("MyTable2", 'd, 'e, 'f)
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Semi1(): Unit = {
+ util.verifyPlan("SELECT * FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Semi2(): Unit = {
+ util.verifyPlan("SELECT b + 1, c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Semi3(): Unit = {
+ util.verifyPlan("SELECT c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2 WHERE b = e)")
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Anti1(): Unit = {
+ util.verifyPlan("SELECT * FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Anti2(): Unit = {
+ util.verifyPlan("SELECT b + 1, c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testNotNeedTransposeProject_Anti3(): Unit = {
+ val sqlQuery =
+ "SELECT c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2 WHERE b = e)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testTransposeProject_Semi1(): Unit = {
+ util.verifyPlan("SELECT a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Semi2(): Unit = {
+ util.verifyPlan("SELECT a + 1 FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Semi3(): Unit = {
+ util.verifyPlan("SELECT a, b FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Semi4(): Unit = {
+ util.verifyPlan("SELECT b, a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Semi5(): Unit = {
+ val sqlQuery = "SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t " +
+ "WHERE a IN (SELECT d FROM MyTable2)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testTransposeProject_Anti1(): Unit = {
+ util.verifyPlan("SELECT a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Anti2(): Unit = {
+ util.verifyPlan( "SELECT a + 1 FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Anti3(): Unit = {
+ util.verifyPlan("SELECT a, b FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Anti4(): Unit = {
+ util.verifyPlan("SELECT b, a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+ }
+
+ @Test
+ def testTransposeProject_Anti5(): Unit = {
+ val sqlQuery = "SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t " +
+ "WHERE a NOT IN (SELECT d FROM MyTable2)"
+ util.verifyPlan(sqlQuery)
+ }
+
+ @Test
+ def testTransposeProject_EmptyProject(): Unit = {
+ util.addTableSource[(Int, Long, String)]("MyTable3", 'i, 'j, 'k)
+ util.addFunction("table_func", new StringSplit)
+
+ val sqlQuery = "SELECT * FROM MyTable1 WHERE EXISTS (" +
+ "SELECT * FROM MyTable2, " +
+ "LATERAL TABLE(table_func(f)) AS T(f1) WHERE EXISTS (SELECT * FROM MyTable3))"
+ util.verifyPlan(sqlQuery)
+ }
+}