[ 
https://issues.apache.org/jira/browse/CALCITE-7554?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

ASF GitHub Bot updated CALCITE-7554:
------------------------------------
    Labels: pull-request-available  (was: )

> NlsString.compareTo() makes TreeSet/TreeMap collapse distinct values with 
> different charset or collation metadata
> -----------------------------------------------------------------------------------------------------------------
>
>                 Key: CALCITE-7554
>                 URL: https://issues.apache.org/jira/browse/CALCITE-7554
>             Project: Calcite
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 1.41.0
>            Reporter: Ruiqi Dong
>            Priority: Major
>              Labels: pull-request-available
>
> *Summary*
> NlsString exposes a natural ordering that can silently merge distinct values 
> in sorted collections. equals() and hashCode() include stringValue, 
> bytesValue, charsetName, and collation. compareTo() compares only the decoded 
> string value, optionally through the collator. As a result, two NlsString 
> objects with identical text but different charset or collation metadata 
> compare as equal in the natural ordering even though they are not equal as 
> objects.
>  
> *Affected code*
> File: core/src/main/java/org/apache/calcite/util/NlsString.java
> {code:java}
> @Override public int hashCode() {
>   return Objects.hash(stringValue, bytesValue, charsetName, collation);
> }
> @Override public boolean equals(@Nullable Object obj) {
>   return this == obj
>       || obj instanceof NlsString
>       && Objects.equals(stringValue, ((NlsString) obj).stringValue)
>       && Objects.equals(bytesValue, ((NlsString) obj).bytesValue)
>       && Objects.equals(charsetName, ((NlsString) obj).charsetName)
>       && Objects.equals(collation, ((NlsString) obj).collation);
> }
> @Override public int compareTo(NlsString other) {
>   if (collation != null && collation.getCollator() != null) {
>     return collation.getCollator().compare(getValue(), other.getValue());
>   }
>   return getValue().compareTo(other.getValue());
> } {code}
>  
> *Reproducer* 
> Add the following test to 
> core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java:
> {code:java}
> @Test void testNlsStringNaturalOrderingKeepsDistinctCharsetMetadata() {
>   final NlsString latin1 =
>       new NlsString("foobar", "LATIN1", SqlCollation.IMPLICIT);
>   final NlsString utf8 =
>       new NlsString("foobar", "UTF8", SqlCollation.IMPLICIT);
>   assertFalse(latin1.equals(utf8));
>   final TreeSet<NlsString> values = new TreeSet<>();
>   values.add(latin1);
>   values.add(utf8);
>   assertThat(values, hasSize(2));
> } {code}
> Run:
> {code:java}
> ./gradlew :core:test \
>   --tests 
> org.apache.calcite.rex.RexBuilderTest.testNlsStringNaturalOrderingKeepsDistinctCharsetMetadata{code}
> Observed behavior:
> The second value is dropped by TreeSet
> {code:java}
> Expected: a collection with size <2>
>      but: collection size was <1> {code}
> Expected behavior:
> If charset or collation metadata makes two NlsString instances unequal, the 
> natural ordering should not treat them as the same sorted-set or sorted-map 
> key.
>  
> This is not just a contract mismatch. NlsString's natural ordering loses 
> metadata that equals() deliberately preserves, so sorted collections keyed by 
> NlsString can silently collapse distinct literals.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to