[CALCITE-7554] NlsString.compareTo inconsistent with equals/hashCode - #5141
Open
lanky228 wants to merge 1 commit into
Open
[CALCITE-7554] NlsString.compareTo inconsistent with equals/hashCode#5141lanky228 wants to merge 1 commit into
lanky228 wants to merge 1 commit into
Conversation
mihaibudiu
reviewed
Aug 2, 2026
| return cmp; | ||
| } | ||
|
|
||
| // Charset: ("hello","LATIN1") vs ("hello","UTF-8") -> not equal |
Contributor
There was a problem hiding this comment.
Please no such comments about past bugs. They will make no sense to future readers.
compareTo() only compared the decoded string, ignoring charset, collation, and byte representation. This broke the compareTo/equals contract: two NlsStrings with same text but different charset would compare as equal, causing TreeSet to silently collapse them. Fix: after string comparison, compare charsetName, collation (via toString()), and bytesValue. Uses Comparator.nullsFirst for null-safe comparison.
|
Contributor
Author
|
Thanks, removed the historical comments. Kept the last line because the byte comparison step is non-obvious and needs explanation. |
Contributor
|
In general please make changes as new commits, so the reviewers can see what's new. |
mihaibudiu
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
NlsString.compareTo()only compared the decoded string value, ignoringcharsetName,collation, andbytesValue. This madecompareToinconsistent withequals()/hashCode(), which consider all metadata fields.Why It Matters
This violates the Java contract: when
equals() == true,compareTo() == 0must also hold. The bug causedTreeSetandTreeMapto silently collapse distinctNlsStringvalues that shared the same decoded string but differed in charset or collation.Example:
("hello", "LATIN1", null)and("hello", "UTF-8", null)are not equal perequals(), but the oldcompareTo()returned 0 — causing aTreeSetto keep only one of them.Changes
NlsString.java(+32 -2):charsetName—Comparator.nullsFirst(String::compareTo)for null safetycollation—SqlCollationdoes not implementComparable, sotoString()is used as proxy keybytesValue—ByteStringimplementsComparable<ByteString>, usingComparator.naturalOrder()Comparator.nullsFirst()for null-safe handling (fields are@Nullable)Comparatorutilities onlyUtilTest.java(+53):testNlsStringCompareToConsistency(): 5 cases verifyingcompareTo/equalsconsistency:compareTo != 0compareTo != 0compareTo == 0compareTo == 0compareTo != 0testNlsStringTreeSetRetainsDistinctValues(): 4 values with same string "hello" but different charset — TreeSet must retain all 4 (before fix: collapsed to 1)Verification
./gradlew :core:compileJava— BUILD SUCCESSFUL./gradlew :core:checkstyleMain— passed./gradlew :core:test --tests "org.apache.calcite.util.UtilTest"— 7 tests passedNote
This is a behavior change:
TreeSet<NlsString>ordering results may differ from before. This is the intended fix — the old behavior was a bug.Jira
CALCITE-7554