chunweilei commented on code in PR #2761:
URL: https://github.com/apache/calcite/pull/2761#discussion_r877681035
##########
core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java:
##########
@@ -225,6 +232,105 @@ protected void perform(RelOptRuleCall call, @Nullable
Filter filter,
call.transformTo(relBuilder.build());
}
+ /**
+ * Infer more equal conditions for the Join Condition.
+ *
+ * <p> For example, in {@code SELECT * FROM T1, T2, T3 WHERE T1.id = T3.id
AND T2.id = T3.id},
+ * we can infer {@code T1.id = T2.id} for the first Join node from second
Join node's condition:
+ * {@code T1.id = T3.id AND T2.id = T3.id}.
+ *
+ * <p>For the above SQL, the second Join's condition is {@code T1.id = T3.id
AND T2.id = T3.id}.
+ * After inference, the final condition would be: {@code T1.id = T2.id AND
T1.id = T3.id}, the
+ * {@code T1.id = T2.id} can be further pushed into LHS.
+ *
+ * @param rexNodes the Join condition
+ * @param join the Join node
+ */
+ protected void inferJoinEqualConditions(List<RexNode> rexNodes, Join join) {
+ final List<Set<Integer>> equalSets = new ArrayList<>();
+ final List<RexNode> result = new ArrayList<>(rexNodes.size());
+ for (RexNode rexNode : rexNodes) {
+ if (rexNode.isA(SqlKind.EQUALS)) {
+ final RexNode op1 = ((RexCall) rexNode).getOperands().get(0);
+ final RexNode op2 = ((RexCall) rexNode).getOperands().get(1);
+ if (op1 instanceof RexInputRef && op2 instanceof RexInputRef) {
+ final RexInputRef in1 = (RexInputRef) op1;
+ final RexInputRef in2 = (RexInputRef) op2;
+ Set<Integer> set = null;
+ for (Set<Integer> s : equalSets) {
+ if (s.contains(in1.getIndex()) || s.contains(in2.getIndex())) {
+ set = s;
+ break;
+ }
+ }
+ if (set == null) {
+ set = new LinkedHashSet<>(); // to make the result deterministic
+ equalSets.add(set);
+ }
+ set.add(in1.getIndex());
+ set.add(in2.getIndex());
+ } else {
+ result.add(rexNode);
+ }
+ } else {
+ result.add(rexNode);
+ }
+ }
+
+ boolean needOptimize = false;
+ for (Set<Integer> set : equalSets) {
+ if (set.size() > 2) {
+ needOptimize = true;
+ break;
+ }
+ }
+ if (!needOptimize) {
+ // keep the conditions unchanged.
+ return;
+ }
+
+ final RexBuilder rexBuilder = join.getCluster().getRexBuilder();
+ for (Set<Integer> set : equalSets) {
+ final List<Integer> leftSet = new ArrayList<>();
+ final List<Integer> rightSet = new ArrayList<>();
+ for (int i : set) {
+ if (i < join.getLeft().getRowType().getFieldCount()) {
+ leftSet.add(i);
Review Comment:
`final int leftRowCount = join.getLeft().getRowType().getFieldCount();` can
be moved to out of the loop.
##########
core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java:
##########
@@ -225,6 +232,132 @@ protected void perform(RelOptRuleCall call, @Nullable
Filter filter,
call.transformTo(relBuilder.build());
}
+ /**
+ * Infer more equal conditions for the Join Condition.
+ *
+ * <p> For example, in {@code SELECT * FROM T1, T2, T3 WHERE T1.id = T3.id
AND T2.id = T3.id},
+ * we can infer {@code T1.id = T2.id} for the first Join node from second
Join node's condition:
+ * {@code T1.id = T3.id AND T2.id = T3.id}.
+ *
+ * <p>For the above SQL, the second Join's condition is {@code T1.id = T3.id
AND T2.id = T3.id}.
+ * After inference, the final condition would be: {@code T1.id = T2.id AND
T1.id = T3.id}, the
+ * {@code T1.id = T2.id} can be further pushed into LHS.
+ *
+ * @param rexNodes the Join condition
+ * @param join the Join node
+ * @return the newly inferred conditions
+ */
+ protected List<RexNode> inferJoinEqualConditions(List<RexNode> rexNodes,
Join join) {
+ final List<RexNode> result = new ArrayList<>(rexNodes.size());
+ final List<Set<Integer>> equalSets = splitEqualSets(rexNodes, result);
+
+ boolean needOptimize = false;
+ for (Set<Integer> set : equalSets) {
+ if (set.size() > 2) {
+ needOptimize = true;
+ break;
+ }
+ }
+ if (!needOptimize) {
+ // keep the conditions unchanged.
+ return rexNodes;
+ }
+
+ result.addAll(constructConditionFromEqualSets(join, equalSets));
+ return result;
+ }
+
+ /**
+ * Split out the equal sets.
+ *
+ * @param rexNodes the original conditions
+ * @param leftNodes where the conditions not feasible for equal sets are put
+ * @return the equal sets
+ */
+ private List<Set<Integer>> splitEqualSets(List<RexNode> rexNodes,
List<RexNode> leftNodes) {
+ final List<Set<Integer>> equalSets = new ArrayList<>();
+ for (RexNode rexNode : rexNodes) {
+ if (rexNode.isA(SqlKind.EQUALS)) {
+ final RexNode op1 = ((RexCall) rexNode).getOperands().get(0);
+ final RexNode op2 = ((RexCall) rexNode).getOperands().get(1);
+ if (op1 instanceof RexInputRef && op2 instanceof RexInputRef) {
+ final RexInputRef in1 = (RexInputRef) op1;
+ final RexInputRef in2 = (RexInputRef) op2;
+ Set<Integer> set = null;
+ for (Set<Integer> s : equalSets) {
+ if (s.contains(in1.getIndex()) || s.contains(in2.getIndex())) {
+ set = s;
+ break;
+ }
+ }
+ if (set == null) {
+ set = new LinkedHashSet<>(); // to make the result deterministic
+ equalSets.add(set);
+ }
+ set.add(in1.getIndex());
+ set.add(in2.getIndex());
+ } else {
+ leftNodes.add(rexNode);
+ }
+ } else {
+ leftNodes.add(rexNode);
+ }
+ }
+
+ return equalSets;
+ }
+
+ /**
+ * Construct new conditions from the equal sets.
+ *
+ * @param join the original {@link Join} node
+ * @param equalSets the equal sets
+ * @return the newly constructed conditions from equal sets
+ */
Review Comment:
Construct new conditions -> Constructs new equal conditions?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]