Ruiqi Dong created CALCITE-7555:
-----------------------------------
Summary: Sarg.compareTo() collapses semantically different search
arguments that have different nullAs
Key: CALCITE-7555
URL: https://issues.apache.org/jira/browse/CALCITE-7555
Project: Calcite
Issue Type: Bug
Components: core
Affects Versions: 1.41.0
Reporter: Ruiqi Dong
*Summary*
Sarg.compareTo() compares only the underlying rangeSet, while equals() and
hashCode() also include nullAs. This means two search arguments over the same
ranges but with different null semantics compare as equal in the natural
ordering even though they are not equal as objects. Any sorted collection keyed
on Sarg can therefore silently merge semantically different values.
*Affected code*
File: core/src/main/java/org/apache/calcite/util/Sarg.java
{code:java}
@Override public int compareTo(Sarg<C> o) {
return RangeSets.compare(rangeSet, o.rangeSet);
}
@Override public int hashCode() {
return RangeSets.hashCode(rangeSet) * 31 + nullAs.ordinal();
}
@Override public boolean equals(@Nullable Object o) {
return o == this
|| o instanceof Sarg
&& nullAs == ((Sarg) o).nullAs
&& rangeSet.equals(((Sarg) o).rangeSet);
} {code}
*Reproducer*
Add the following test to
core/src/test/java/org/apache/calcite/util/MtClawCalciteBugTest.jav
{code:java}
@Test void testSargNaturalOrderingKeepsDistinctNullSemantics() {
final ImmutableRangeSet<Integer> singleton =
ImmutableRangeSet.of(Range.singleton(1));
final Sarg<Integer> unknown =
Sarg.of(RexUnknownAs.UNKNOWN, singleton);
final Sarg<Integer> falseSarg =
Sarg.of(RexUnknownAs.FALSE, singleton);
assertFalse(unknown.equals(falseSarg));
final TreeSet<Sarg<Integer>> values = new TreeSet<>();
values.add(unknown);
values.add(falseSarg);
assertThat(values, hasSize(2));
} {code}
Run:
{code:java}
./gradlew :core:test \
--tests
org.apache.calcite.util.MtClawCalciteBugTest.testSargNaturalOrderingKeepsDistinctNullSemantics
{code}
Observed behavior:
The test fails because the natural ordering collapses the two distinct Sarg
values
{code:java}
Expected: a collection with size <2>
but: collection size was <1> {code}
Expected behavior:
nullAs changes the meaning of a search argument. Two Sarg instances that differ
in nullAs should not compare as the same element in sorted collections.
This is a semantic bug, not just a Comparable cleanliness issue. A Sarg is more
than its range set. nullAs changes SQL three-valued semantics, but compareTo()
ignores it completely and allows sorted collections to merge semantically
different search arguments.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)