Code review comment: The handling of null values, using constant folding, is more general and does not require writing long logical judgments

Code under review:
public Rule build() {
        return logicalFilter(logicalJoin())
                .when(filter -> filter.child().getJoinType().isOuterJoin())
                .then(filter -> {
                    List<Expression> predicates = ExpressionUtils.extractConjunction(filter.getPredicates());
                    Set<Slot> notNullSlots = new HashSet<>();
                    for (Expression predicate : predicates) {
                        
                        if (predicate instanceof ComparisonPredicate) {
                            notNullSlots.addAll(predicate.getInputSlots());
                        }
                    }
                    LogicalJoin<GroupPlan, GroupPlan> join = filter.child();
                    JoinType joinType = join.getJoinType();
                    if (!joinType.isLeftOuterJoin() && ExpressionUtils.isIntersecting(join.left().getOutputSet(),
                            notNullSlots)) {
                        joinType = ELIMINATE_RIGHT_MAP.get(joinType);
                    }
                    if (!joinType.isRightOuterJoin() && ExpressionUtils.isIntersecting(join.right().getOutputSet(),
                            notNullSlots)) {
                        joinType = ELIMINATE_LEFT_MAP.get(joinType);
                    }

                    if (joinType == join.getJoinType()) {
                        return null;
                    }

                    return new LogicalFilter<>(filter.getPredicates(),
                            new LogicalJoin<>(joinType,
                                    join.getHashJoinConjuncts(), join.getOtherJoinCondition(),
                                    join.left(), join.right()));
                }).toRule(RuleType.ELIMINATE_OUTER);
    }

Line commented on: if (!joinType.isLeftOuterJoin() && ExpressionUtils.isIntersecting(join.left().getOutputSet(),

Revised code:
public Rule build() {
        return logicalFilter(logicalJoin())
                .when(filter -> filter.child().getJoinType().isOuterJoin())
                .then(filter -> {
                    List<Expression> predicates = ExpressionUtils.extractConjunction(filter.getPredicates());
                    Set<Slot> notNullSlots = new HashSet<>();
                    for (Expression predicate : predicates) {
                        
                        if (predicate instanceof ComparisonPredicate) {
                            notNullSlots.addAll(predicate.getInputSlots());
                        }
                    }
                    LogicalJoin<GroupPlan, GroupPlan> join = filter.child();
                    JoinType joinType = join.getJoinType();
                    if (!joinType.isLeftOuterJoin() && ExpressionUtils.isIntersecting(join.left().getOutputSet(),
                            notNullSlots)) {
                        joinType = ELIMINATE_RIGHT_MAP.get(joinType);
                    }
                    if (!joinType.isRightOuterJoin() && ExpressionUtils.isIntersecting(join.right().getOutputSet(),
                            notNullSlots)) {
                        joinType = ELIMINATE_LEFT_MAP.get(joinType);
                    }

                    if (joinType == join.getJoinType()) {
                        return null;
                    }

                    return new LogicalFilter<>(filter.getPredicates(),
                            new LogicalJoin<>(joinType,
                                    join.getHashJoinConjuncts(), join.getOtherJoinCondition(),
                                    join.left(), join.right()));
                }).toRule(RuleType.ELIMINATE_OUTER);
    }