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);
}