Repository navigation
Conversation
castDoubleToInt rounded (float) value, so in-range doubles above 2^24, or just below a .5 tie, were changed before rounding (123456789.0 became 123456792 and 2.4999999999 became 3). Round the double directly; the existing range check keeps the result within int, so the narrowing from long cannot overflow. Closes apache#19274
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.
Description
Closes #19274
Root cause
CastFunctionUtils.castDoubleToIntrounded(float) value. A FLOAT keeps only 24 significand bits, so in-range doubles above 2^24 can change before they are rounded, and doubles just below a.5tie can be moved onto the tie. For example,123456789.0came out as123456792and2.4999999999as3. Every DOUBLE to INT32 cast goes through this method: the per-value and batch column casts in the tree and table models, and table-model constant folding.Change
This matches
castDoubleToLongand the documented rule for DOUBLE to INT32 ("Math.round()"). The range check above it is unchanged. It limits the value to [Integer.MIN_VALUE, Integer.MAX_VALUE], soMath.round(value)stays within int range and the cast fromlongcannot overflow. Half values keep their existing behaviour (2.5 -> 3, -2.5 -> -2), and out-of-range values still throw.Tests
New cases in
CastFunctionUtilsTest:castDoubleToIntKeepsDoublePrecision: 16777217, ±123456789, 2147483000, 2147483646, -2147483647, Integer.MAX_VALUE, Integer.MIN_VALUE, 2.4999999999 and 100000001.5castDoubleToIntRoundsHalfUp: 2.5, -1.5 and -2.5castDoubleToIntJustAboveMax/castDoubleToIntJustBelowMin: 2147483648.0 and -2147483649.0 throwSemanticExceptionResults with
./mvnw -pl iotdb-core/calc-commons test -Dtest=CastFunctionUtilsTest(Temurin JDK 25.0.2, macOS arm64):Before the fix:
After the fix:
./mvnw -pl iotdb-core/calc-commons test(whole module) also passes:Tests run: 91, Failures: 0, Errors: 0, Skipped: 0. Spotless check passes.I also ran the SQL from #19274 on a standalone
2.0.11-SNAPSHOTserver with the patched class. Tree, table and constant-folded casts now return the same values asCAST(... AS INT64):SELECT CAST(2147483648.0 AS INT32)still fails with701: Double value 2147483648.000000 is out of range of integer value., andTRY_CAST(-2147483649.0 AS INT32)returns null.Not run locally: the integration-test suites (
IoTDBCastFunctionIT,IoTDBCastFunctionTableIT) and the datanode module tests. I checked that no existing IT asserts the old FLOAT-rounded values.This PR has:
for code coverage.
Key changed/added classes (or packages if there are too many classes) in this PR
CastFunctionUtils(calc-commons)CastFunctionUtilsTest