This is an automated email from the ASF dual-hosted git repository.
xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new cb8eabca329 [core] Fix truncate(value) signed-zero and non-finite
behavior (#17677)
cb8eabca329 is described below
commit cb8eabca3296709d0cb7041e7743ee9b52390ecf
Author: Xiang Fu <[email protected]>
AuthorDate: Wed Feb 11 19:57:46 2026 -0800
[core] Fix truncate(value) signed-zero and non-finite behavior (#17677)
---
.../function/TruncateDecimalTransformFunction.java | 17 ++++++++++-
.../TruncateDecimalTransformFunctionTest.java | 35 ++++++++++++++++++++++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunction.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunction.java
index 9dfb0c65157..8b75d7eca78 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunction.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunction.java
@@ -98,7 +98,22 @@ public class TruncateDecimalTransformFunction extends
BaseTransformFunction {
}
} else {
for (int i = 0; i < length; i++) {
- _doubleValuesSV[i] = Math.signum(leftValues[i]) *
Math.floor(Math.abs(leftValues[i]));
+ double value = leftValues[i];
+ if (!Double.isFinite(value)) {
+ // Preserve historical behavior for NaN and infinities.
+ _doubleValuesSV[i] = value;
+ continue;
+ }
+ double truncated;
+ if (value > 0.0d) {
+ truncated = Math.floor(value);
+ } else if (value < 0.0d) {
+ truncated = Math.ceil(value);
+ } else {
+ truncated = 0.0d;
+ }
+ // Normalize -0.0 to +0.0 for deterministic output and test stability.
+ _doubleValuesSV[i] = truncated == 0.0d ? 0.0d : truncated;
}
}
return _doubleValuesSV;
diff --git
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunctionTest.java
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunctionTest.java
index 05ea6c88886..d8b7858366c 100644
---
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunctionTest.java
+++
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/TruncateDecimalTransformFunctionTest.java
@@ -20,6 +20,7 @@ package org.apache.pinot.core.operator.transform.function;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.util.Arrays;
import org.apache.pinot.common.function.TransformFunctionType;
import org.apache.pinot.common.request.context.ExpressionContext;
import org.apache.pinot.common.request.context.RequestContextUtils;
@@ -62,12 +63,46 @@ public class TruncateDecimalTransformFunctionTest extends
BaseTransformFunctionT
expectedValues[i] = truncate(_doubleSVValues[i], 0);
}
testTransformFunction(transformFunction, expectedValues);
+
+ // Regression for signed-zero handling: truncate(value) should match
truncate(value, 0).
+ expression = RequestContextUtils.getExpression("truncate(-0.4)");
+ transformFunction = TransformFunctionFactory.get(expression,
_dataSourceMap);
+ Assert.assertTrue(transformFunction instanceof
TruncateDecimalTransformFunction);
+ Arrays.fill(expectedValues, 0.0d);
+ testTransformFunction(transformFunction, expectedValues);
+
+ long positiveZeroBits = Double.doubleToRawLongBits(0.0d);
+ double[] actualValues =
transformFunction.transformToDoubleValuesSV(_projectionBlock);
+ for (double actualValue : actualValues) {
+ Assert.assertEquals(Double.doubleToRawLongBits(actualValue),
positiveZeroBits);
+ }
+ }
+
+ @Test
+ public void testTruncateNaNAndInfinity() {
+ testTruncateLiteralNoScale(
+ String.format("truncate((%s - %s) / (%s - %s))", INT_SV_COLUMN,
INT_SV_COLUMN, INT_SV_COLUMN, INT_SV_COLUMN),
+ Double.NaN);
+ testTruncateLiteralNoScale(String.format("truncate(1.0 / (%s - %s))",
INT_SV_COLUMN, INT_SV_COLUMN),
+ Double.POSITIVE_INFINITY);
+ testTruncateLiteralNoScale(String.format("truncate(-1.0 / (%s - %s))",
INT_SV_COLUMN, INT_SV_COLUMN),
+ Double.NEGATIVE_INFINITY);
}
public Double truncate(double a, int b) {
return BigDecimal.valueOf(a).setScale(b, RoundingMode.DOWN).doubleValue();
}
+ private void testTruncateLiteralNoScale(String expressionString, double
expectedValue) {
+ ExpressionContext expression =
RequestContextUtils.getExpression(expressionString);
+ TransformFunction transformFunction =
TransformFunctionFactory.get(expression, _dataSourceMap);
+ Assert.assertTrue(transformFunction instanceof
TruncateDecimalTransformFunction);
+ Assert.assertEquals(transformFunction.getName(),
TransformFunctionType.TRUNCATE.getName());
+ double[] expectedValues = new double[NUM_ROWS];
+ Arrays.fill(expectedValues, expectedValue);
+ testTransformFunction(transformFunction, expectedValues);
+ }
+
@Test
public void testTruncateNullLiteral() {
ExpressionContext expression =
RequestContextUtils.getExpression("truncate(null, 1)");
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]