alex-plekhanov commented on code in PR #11972:
URL: https://github.com/apache/ignite/pull/11972#discussion_r2030955054
##########
modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgnitePlanner.java:
##########
@@ -586,6 +590,117 @@ private RelNode
visitLeftAndRightCorrelateHands(LogicalCorrelate correlate, Corr
return relShuttle.visit(rel);
}
+ /**
+ * Due to distributive property of conjunction over disjunction we can
extract common part of conjunctions.
+ * This can help us to simplify and push down filters.
+ * For example, condition:
+ * (a = 0 and x = 1) or (a = 0 and y = 2) or (a = 0 and z = 3)
+ * can be translated to:
+ * a = 0 and (x = 1 or y = 2 or z = 3)
+ * after such a transformation condition "a = 0" can be used as index
access predicate.
+ */
+ public RelNode extractConjunctionOverDisjunctionCommonPart(RelNode rel) {
+ return new RelHomogeneousShuttle() {
+ /** {@inheritDoc} */
+ @Override public RelNode visit(LogicalFilter filter) {
+ RexNode condition =
transform(filter.getCluster().getRexBuilder(), filter.getCondition());
+
+ if (condition != filter.getCondition())
+ filter = filter.copy(filter.getTraitSet(),
filter.getInput(), condition);
+
+ return super.visit(filter);
+ }
+
+ /** {@inheritDoc} */
+ @Override public RelNode visit(LogicalJoin join) {
+ RexNode condition =
transform(join.getCluster().getRexBuilder(), join.getCondition());
+
+ if (condition != join.getCondition()) {
+ join = join.copy(join.getTraitSet(), condition,
join.getLeft(), join.getRight(),
+ join.getJoinType(), join.isSemiJoinDone());
+ }
+
+ return super.visit(join);
+ }
+
+ /** */
+ private RexNode transform(RexBuilder rexBuilder, RexNode
condition) {
+ // It makes sence to extract only top level disjunction common
part.
+ if (!condition.isA(SqlKind.OR))
+ return condition;
+
+ Set<RexNode> commonPart = new HashSet<>();
+
+ List<RexNode> orOps = ((RexCall)condition).getOperands();
+
+ RexNode firstOp = orOps.get(0);
+
+ for (RexNode andOpFirst : conjunctionOperands(firstOp)) {
+ boolean found = false;
+
+ for (int i = 1; i < orOps.size(); i++) {
+ found = false;
+
+ for (RexNode andOpOther :
conjunctionOperands(orOps.get(i))) {
+ if (andOpFirst.equals(andOpOther)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ break;
+ }
+
+ if (found)
+ commonPart.add(andOpFirst);
+ }
+
+ if (commonPart.isEmpty())
+ return condition;
+
+ List<RexNode> newOrOps = new ArrayList<>(orOps.size());
+
+ for (RexNode orOp : orOps) {
+ List<RexNode> newAndOps = new ArrayList<>();
+
+ for (RexNode andOp : conjunctionOperands(orOp)) {
+ if (!commonPart.contains(andOp))
+ newAndOps.add(andOp);
+ }
+
+ if (!newAndOps.isEmpty()) {
+ RexNode newAnd =
RexUtil.composeConjunction(rexBuilder, newAndOps);
Review Comment:
Almos all tests in `testExtractCommonDisjunctionPart` have `newOrOps.size()
> 1`. "Three operands disjunction" has `newOrOps.size() == 3`, for example.
--
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]