private static SearchBounds createBounds()

in modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/util/RexUtils.java [324:515]


    private static SearchBounds createBounds(
        @Nullable RelFieldCollation fc, // Can be null for EQUALS condition.
        List<RexCall> collFldPreds,
        RelOptCluster cluster,
        RelDataType fldType,
        int prevComplexity
    ) {
        RexBuilder builder = builder(cluster);

        RexNode nullBound = builder.makeCall(IgniteOwnSqlOperatorTable.NULL_BOUND);

        RexNode upperCond = null;
        RexNode lowerCond = null;
        RexNode upperBound = null;
        RexNode lowerBound = null;
        boolean upperInclude = true;
        boolean lowerInclude = true;

        // Give priority to equality operators.
        collFldPreds.sort(Comparator.comparingInt(pred -> {
            switch (pred.getOperator().getKind()) {
                case EQUALS:
                case IS_NOT_DISTINCT_FROM:
                case IS_NULL:
                    return 0;
                default:
                    return 1;
            }
        }));

        for (RexCall pred : collFldPreds) {
            RexNode val = null;
            RexNode ref = pred.getOperands().get(0);

            if (isBinaryComparison(pred)) {
                val = removeCast(pred.operands.get(1));

                assert idxOpSupports(val) : val;

                val = makeCast(builder, val, fldType);
            }

            SqlOperator op = pred.getOperator();

            if (op.kind == EQUALS)
                return new ExactBounds(pred, val);
            if (op.kind == IS_NOT_DISTINCT_FROM)
                return new ExactBounds(pred, builder.makeCall(SqlStdOperatorTable.COALESCE, val, nullBound));
            else if (op.kind == IS_NULL)
                return new ExactBounds(pred, nullBound);
            else if (op.kind == OR) {
                List<SearchBounds> orBounds = new ArrayList<>();
                int curComplexity = 0;

                for (RexNode operand : pred.getOperands()) {
                    SearchBounds opBounds = createBounds(fc, Collections.singletonList((RexCall)operand),
                        cluster, fldType, prevComplexity);

                    if (opBounds instanceof MultiBounds) {
                        curComplexity += ((MultiBounds)opBounds).bounds().size();
                        orBounds.addAll(((MultiBounds)opBounds).bounds());
                    }
                    else if (opBounds != null) {
                        curComplexity++;
                        orBounds.add(opBounds);
                    }

                    if (opBounds == null || curComplexity > MAX_SEARCH_BOUNDS_COMPLEXITY) {
                        orBounds = null;
                        break;
                    }
                }

                if (orBounds == null)
                    continue;

                return new MultiBounds(pred, orBounds);
            }
            else if (op.kind == SEARCH) {
                Sarg<?> sarg = ((RexLiteral)pred.operands.get(1)).getValueAs(Sarg.class);

                List<SearchBounds> bounds = expandSargToBounds(fc, cluster, fldType, prevComplexity, sarg, ref);

                if (bounds == null)
                    continue;

                if (bounds.size() == 1) {
                    if (bounds.get(0) instanceof RangeBounds && collFldPreds.size() > 1) {
                        // Try to merge bounds.
                        boolean ascDir = !fc.getDirection().isDescending();
                        RangeBounds rangeBounds = (RangeBounds)bounds.get(0);
                        if (rangeBounds.lowerBound() != null) {
                            if (lowerBound != null && lowerBound != nullBound) {
                                lowerBound = leastOrGreatest(builder, !ascDir, lowerBound, rangeBounds.lowerBound());
                                lowerInclude |= rangeBounds.lowerInclude();
                            }
                            else {
                                lowerBound = rangeBounds.lowerBound();
                                lowerInclude = rangeBounds.lowerInclude();
                            }
                            lowerCond = lessOrGreater(builder, !ascDir, lowerInclude, ref, lowerBound);
                        }

                        if (rangeBounds.upperBound() != null) {
                            if (upperBound != null && upperBound != nullBound) {
                                upperBound = leastOrGreatest(builder, ascDir, upperBound, rangeBounds.upperBound());
                                upperInclude |= rangeBounds.upperInclude();
                            }
                            else {
                                upperBound = rangeBounds.upperBound();
                                upperInclude = rangeBounds.upperInclude();
                            }
                            upperCond = lessOrGreater(builder, ascDir, upperInclude, ref, upperBound);
                        }

                        continue;
                    }
                    else
                        return bounds.get(0);
                }

                return new MultiBounds(pred, bounds);
            }

            // Range bounds.
            boolean lowerBoundBelow = !fc.getDirection().isDescending();
            boolean includeBound = op.kind == GREATER_THAN_OR_EQUAL || op.kind == LESS_THAN_OR_EQUAL;
            boolean lessCondition = false;

            switch (op.kind) {
                case LESS_THAN:
                case LESS_THAN_OR_EQUAL:
                    lessCondition = true;
                    lowerBoundBelow = !lowerBoundBelow;
                    // Fall through.

                case GREATER_THAN:
                case GREATER_THAN_OR_EQUAL:
                    if (lowerBoundBelow) {
                        if (lowerBound == null || lowerBound == nullBound) {
                            lowerCond = pred;
                            lowerBound = val;
                            lowerInclude = includeBound;
                        }
                        else {
                            lowerBound = leastOrGreatest(builder, lessCondition, lowerBound, val);
                            lowerInclude |= includeBound;
                            lowerCond = lessOrGreater(builder, lessCondition, lowerInclude, ref, lowerBound);
                        }
                    }
                    else {
                        if (upperBound == null || upperBound == nullBound) {
                            upperCond = pred;
                            upperBound = val;
                            upperInclude = includeBound;
                        }
                        else {
                            upperBound = leastOrGreatest(builder, lessCondition, upperBound, val);
                            upperInclude |= includeBound;
                            upperCond = lessOrGreater(builder, lessCondition, upperInclude, ref, upperBound);
                        }
                    }
                    // Fall through.

                case IS_NOT_NULL:
                    if (fc.nullDirection == RelFieldCollation.NullDirection.FIRST && lowerBound == null) {
                        lowerCond = pred;
                        lowerBound = nullBound;
                        lowerInclude = false;
                    }
                    else if (fc.nullDirection == RelFieldCollation.NullDirection.LAST && upperBound == null) {
                        upperCond = pred;
                        upperBound = nullBound;
                        upperInclude = false;
                    }
                    break;

                default:
                    throw new AssertionError("Unknown condition: " + op.kind);
            }
        }

        if (lowerBound == null && upperBound == null)
            return null; // No bounds.

        // Found upper bound, lower bound or both.
        RexNode cond = lowerCond == null ? upperCond :
            upperCond == null ? lowerCond :
                upperCond == lowerCond ? lowerCond : builder.makeCall(SqlStdOperatorTable.AND, lowerCond, upperCond);

        return new RangeBounds(cond, lowerBound, upperBound, lowerInclude, upperInclude);
    }