Skip to content

Commit

Permalink
[fix](nereids) fix range inference generate an empty range (#47434)
Browse files Browse the repository at this point in the history
for `a >= 8 and a <8` will generate a range(a>=8) interset range(a <8) =
range[8, 8), this is a empty range.

PR #46303 introduce a RangeSet to hold the union of RangeValues, for a
empty range[8, 8), RangeSet.asRanges() will return empty. Then cause a
index out of bound exception.

```
Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
        at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) ~[?:?]
        at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) ~[?:?]
        at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266) ~[?:?]
        at java.util.Objects.checkIndex(Objects.java:359) ~[?:?]
        at java.util.ArrayList.get(ArrayList.java:427) ~[?:?]
        at org.apache.doris.nereids.rules.expression.rules.RangeInference.simplify(RangeInference.java:166) ~[doris-fe.jar:1.2-SNAPSHOT]
        at org.apache.doris.nereids.rules.expression.rules.RangeInference.visitOr(RangeInference.java:130) ~[doris-fe.jar:1.2-SNAPSHOT]
        at org.apache.doris.nereids.rules.expression.rules.RangeInference.visitOr(RangeInference.java:59) ~[doris-fe.jar:1.2-SNAPSHOT]
```

Fix: for a empty RangeValue like [8, 8), replace it with an EmptyValue.

What's more, this PR will also replace singleton RangeValue like ([8,
8]) to DiscreteValue([8]), so after this PR, simplify range will rewrite
`a >= 8 and a <= 8` to `a = 8`. This is just BetweenToEqual rule do.
After this PR, we can remove rule BetweenToEqual.
  • Loading branch information
yujun777 authored Feb 12, 2025
1 parent 3692aba commit ea15769
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,16 @@ private Map<Expression, MinMaxValue> getExprMinMaxValues(UnknownValue valueDesc)
value.range = null;
} else if (value.range != null) {
if (value.range.isConnected(otherValue.range)) {
value.range = value.range.intersection(otherValue.range);
value.isDiscrete = value.isDiscrete && otherValue.isDiscrete;
Range<ComparableLiteral> newRange = value.range.intersection(otherValue.range);
if (!newRange.isEmpty()) {
value.range = newRange;
// If newRange.lowerEndpoint().equals(newRange.upperEndpoint()),
// then isDiscrete should be true.
// But no need to do that because AddMinMax will not handle discrete value cases.
value.isDiscrete = value.isDiscrete && otherValue.isDiscrete;
} else {
value.range = null;
}
} else {
value.range = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,17 @@ public ValueDesc intersect(ValueDesc other) {
if (other instanceof RangeValue) {
RangeValue o = (RangeValue) other;
if (range.isConnected(o.range)) {
return new RangeValue(context, reference, range.intersection(o.range));
Range<ComparableLiteral> newRange = range.intersection(o.range);
if (!newRange.isEmpty()) {
if (newRange.hasLowerBound() && newRange.hasUpperBound()
&& newRange.lowerEndpoint().compareTo(newRange.upperEndpoint()) == 0
&& newRange.lowerBoundType() == BoundType.CLOSED
&& newRange.lowerBoundType() == BoundType.CLOSED) {
return new DiscreteValue(context, reference, Sets.newHashSet(newRange.lowerEndpoint()));
} else {
return new RangeValue(context, reference, newRange);
}
}
}
return new EmptyValue(context, reference);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ void testAddMinMax() {
assertRewriteAfterTypeCoercion("(TA + TC > 10 and TB > 10) or (TB > 10 and TB > 20)", "(TA + TC > 10 or TB > 20) AND TB > 10");
assertRewriteAfterTypeCoercion("((TA + TC > 10 or TA + TC > 5) and TB > 10) or (TB > 10 and (TB > 20 or TB < 10))",
"((TA + TC > 10 or TA + TC > 5) or (TB > 20 or TB < 10)) and TB > 10");
assertRewriteAfterTypeCoercion("TA >= 8 and TB >= 1 or TA < 8 and TB <= 10",
"TA >= 8 and TB >= 1 or TA < 8 and TB <= 10");
assertRewriteAfterTypeCoercion("TA >= 8 and TB >= 1 and TA < 8 and TB <= 10",
"TA >= 8 and TB >= 1 and TA < 8 and TB <= 10");
assertRewriteAfterTypeCoercion("(CA >= date '2024-01-01' and CA <= date '2024-01-03') or (CA > date '2024-01-05' and CA < date '2024-01-07')",
"(CA <= date '2024-01-03' or CA > date '2024-01-05') and CA >= date '2024-01-01' and CA < date '2024-01-07')");
assertRewriteAfterTypeCoercion("CA in (date '2024-01-01',date '2024-01-02',date '2024-01-03') or CA < date '2024-01-01'",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@ public void testSimplify() {
assertRewrite("(TA > 3 and TA < 1) or (TA > 7 and TA < 5)", "TA is null and null");
assertRewriteNotNull("TA > 3 and TA < 1", "FALSE");
assertRewrite("TA > 3 and TA < 1", "TA is null and null");
assertRewrite("TA >= 3 and TA < 3", "TA >= 3 and TA < 3");
assertRewrite("TA >= 3 and TA < 3", "TA is null and null");
assertRewriteNotNull("TA = 1 and TA > 10", "FALSE");
assertRewrite("TA = 1 and TA > 10", "TA is null and null");
assertRewrite("TA >= 1 and TA <= 1", "TA = 1");
assertRewrite("TA > 5 or TA < 1", "TA < 1 or TA > 5");
assertRewrite("TA > 5 or TA > 1 or TA > 10", "TA > 1");
assertRewrite("TA > 5 or TA > 1 or TA < 10", "TA is not null or null");
Expand Down Expand Up @@ -176,7 +177,7 @@ public void testSimplify() {
assertRewrite("(TA + TC > 3 and TA + TC < 1) or (TA + TC > 7 and TA + TC < 5)", "(TA + TC) is null and null");
assertRewriteNotNull("TA + TC > 3 and TA + TC < 1", "FALSE");
assertRewrite("TA + TC > 3 and TA + TC < 1", "(TA + TC) is null and null");
assertRewrite("TA + TC >= 3 and TA + TC < 3", "TA + TC >= 3 and TA + TC < 3");
assertRewrite("TA + TC >= 3 and TA + TC < 3", "TA + TC is null and null");
assertRewriteNotNull("TA + TC = 1 and TA + TC > 10", "FALSE");
assertRewrite("TA + TC = 1 and TA + TC > 10", "(TA + TC) is null and null");
assertRewrite("TA + TC > 5 or TA + TC < 1", "TA + TC < 1 or TA + TC > 5");
Expand Down Expand Up @@ -246,7 +247,7 @@ public void testSimplifyDate() {
assertRewriteNotNull("AA > date '2024-01-03' and AA < date '2024-01-01'", "FALSE");
assertRewrite("AA > date '2024-01-03' and AA < date '2024-01-01'", "AA is null and null");
assertRewrite("AA >= date '2024-01-01' and AA < date '2024-01-01'",
"AA >= date '2024-01-01' and AA < date '2024-01-01'");
"AA IS NULL AND NULL");
assertRewriteNotNull("AA = date '2024-01-01' and AA > date '2024-01-10'", "FALSE");
assertRewrite("AA = date '2024-01-01' and AA > date '2024-01-10'", "AA is null and null");
assertRewrite("AA > date '2024-01-05' or AA < date '2024-01-01'",
Expand Down Expand Up @@ -326,7 +327,7 @@ public void testSimplifyDateTime() {
assertRewriteNotNull("CA > timestamp '2024-01-03 00:00:10' and CA < timestamp '2024-01-01 01:00:00'", "FALSE");
assertRewrite("CA > timestamp '2024-01-03 00:00:10' and CA < timestamp '2024-01-01 01:00:00'", "CA is null and null");
assertRewrite("CA >= timestamp '2024-01-01 00:00:10' and CA < timestamp '2024-01-01 00:00:10'",
"CA >= timestamp '2024-01-01 00:00:10' and CA < timestamp '2024-01-01 00:00:10'");
"CA is null and null");
assertRewriteNotNull("CA = timestamp '2024-01-01 10:00:10' and CA > timestamp '2024-01-10 00:00:10'", "FALSE");
assertRewrite("CA = timestamp '2024-01-01 10:00:10' and CA > timestamp '2024-01-10 00:00:10'", "CA is null and null");
assertRewrite("CA > timestamp '2024-01-05 00:00:10' or CA < timestamp '2024-01-01 00:00:10'",
Expand Down

0 comments on commit ea15769

Please sign in to comment.