diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/operator/scalar/ConstantOperator.java b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/operator/scalar/ConstantOperator.java index 7afe9ab23e0..a9734ea838e 100644 --- a/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/operator/scalar/ConstantOperator.java +++ b/fe/fe-core/src/main/java/com/starrocks/sql/optimizer/operator/scalar/ConstantOperator.java @@ -677,11 +677,11 @@ public final class ConstantOperator extends ScalarOperator implements Comparable public long distance(ConstantOperator other) { if (type.isTinyint()) { - return other.getTinyInt() - getTinyInt(); + return (long) other.getTinyInt() - (long) getTinyInt(); } else if (type.isSmallint()) { - return other.getSmallint() - getSmallint(); + return (long) other.getSmallint() - (long) getSmallint(); } else if (type.isInt()) { - return other.getInt() - getInt(); + return (long) other.getInt() - (long) getInt(); } else if (type.isBigint()) { return other.getBigint() - getBigint(); } else if (type.isLargeint()) { diff --git a/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/operator/operator/ConstantOperatorTest.java b/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/operator/operator/ConstantOperatorTest.java index f03175dcfc0..0f07e0475d5 100644 --- a/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/operator/operator/ConstantOperatorTest.java +++ b/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/operator/operator/ConstantOperatorTest.java @@ -158,6 +158,12 @@ public class ConstantOperatorTest { ConstantOperator var2 = ConstantOperator.createTinyInt((byte) 20); Assertions.assertEquals(10, var1.distance(var2)); Assertions.assertEquals(-10, var2.distance(var1)); + + // tinyint edge cases + ConstantOperator tinyMax = ConstantOperator.createTinyInt(Byte.MAX_VALUE); + ConstantOperator tinyMin = ConstantOperator.createTinyInt(Byte.MIN_VALUE); + Assertions.assertEquals(255L, tinyMax.distance(tinyMin)); + Assertions.assertEquals(-255L, tinyMin.distance(tinyMax)); } { @@ -166,6 +172,12 @@ public class ConstantOperatorTest { ConstantOperator var2 = ConstantOperator.createSmallInt((short) 20); Assertions.assertEquals(10, var1.distance(var2)); Assertions.assertEquals(-10, var2.distance(var1)); + + // smallint edge cases + ConstantOperator smallMax = ConstantOperator.createSmallInt(Short.MAX_VALUE); + ConstantOperator smallMin = ConstantOperator.createSmallInt(Short.MIN_VALUE); + Assertions.assertEquals(65535L, smallMax.distance(smallMin)); + Assertions.assertEquals(-65535L, smallMin.distance(smallMax)); } { @@ -176,6 +188,27 @@ public class ConstantOperatorTest { Assertions.assertEquals(-10, var2.distance(var1)); } + { + // int edge cases - test for integer overflow fix + ConstantOperator intMax = ConstantOperator.createInt(Integer.MAX_VALUE); + ConstantOperator intMin = ConstantOperator.createInt(Integer.MIN_VALUE); + ConstantOperator testValue = ConstantOperator.createInt(1234567890); + ConstantOperator zero = ConstantOperator.createInt(0); + + // Test case that previously caused overflow: INT_MAX - INT_MIN should be 4294967295 + Assertions.assertEquals(4294967295L, intMax.distance(intMin)); + Assertions.assertEquals(-4294967295L, intMin.distance(intMax)); + + // Test case from issue #63669: test_value - INT_MIN should be 3382051538 + Assertions.assertEquals(3382051538L, testValue.distance(intMin)); + + // Test case: INT_MAX - test_value should be 912915757 + Assertions.assertEquals(912915757L, intMax.distance(testValue)); + + // Test case: zero - INT_MIN should be 2147483648 + Assertions.assertEquals(2147483648L, zero.distance(intMin)); + } + { // long ConstantOperator var1 = ConstantOperator.createBigint(10); diff --git a/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/rule/transformation/materialization/Int32PredicateTest.java b/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/rule/transformation/materialization/Int32PredicateTest.java new file mode 100644 index 00000000000..374269dc619 --- /dev/null +++ b/fe/fe-core/src/test/java/com/starrocks/sql/optimizer/rule/transformation/materialization/Int32PredicateTest.java @@ -0,0 +1,115 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.starrocks.sql.optimizer.rule.transformation.materialization; + +import com.starrocks.catalog.Type; +import com.starrocks.sql.ast.expression.BinaryType; +import com.starrocks.sql.optimizer.operator.scalar.BinaryPredicateOperator; +import com.starrocks.sql.optimizer.operator.scalar.ColumnRefOperator; +import com.starrocks.sql.optimizer.operator.scalar.ConstantOperator; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Test case for issue #63669: FE Assertion Failure when querying on int32 column in WHERE clause + */ +public class Int32PredicateTest { + + @Test + public void testInt32PredicateWithLargeValue() { + // Reproduce the issue scenario: WHERE collect_api_receive_time = 1234567890 + ColumnRefOperator columnRef = new ColumnRefOperator(1, Type.INT, "collect_api_receive_time", true); + ConstantOperator value = ConstantOperator.createInt(1234567890); + + // Create a binary predicate: collect_api_receive_time = 1234567890 + BinaryPredicateOperator pred = new BinaryPredicateOperator(BinaryType.EQ, columnRef, value); + + // This should not throw an assertion failure anymore + Assertions.assertNotNull(pred); + Assertions.assertEquals(BinaryType.EQ, pred.getBinaryType()); + Assertions.assertEquals(columnRef, pred.getChild(0)); + Assertions.assertEquals(value, pred.getChild(1)); + + // Test the distance calculation that was causing the issue + ConstantOperator intMin = ConstantOperator.createInt(Integer.MIN_VALUE); + long distance = value.distance(intMin); + Assertions.assertEquals(3382051538L, distance); + } + + @Test + public void testInt32PredicateExtraction() { + // Test predicate extraction which involves range canonicalization + ColumnRefOperator columnRef = new ColumnRefOperator(1, Type.INT, "test_column", true); + ConstantOperator value = ConstantOperator.createInt(1234567890); + + // Create equality predicate + BinaryPredicateOperator eqPred = new BinaryPredicateOperator(BinaryType.EQ, columnRef, value); + + // Create greater than predicate + BinaryPredicateOperator gtPred = new BinaryPredicateOperator(BinaryType.GT, columnRef, value); + + // Create less than predicate + BinaryPredicateOperator ltPred = new BinaryPredicateOperator(BinaryType.LT, columnRef, value); + + // These should not cause assertion failures + PredicateExtractor extractor = new PredicateExtractor(); + PredicateExtractor.PredicateExtractorContext context = new PredicateExtractor.PredicateExtractorContext(); + + try { + RangePredicate eqRange = extractor.visitBinaryPredicate(eqPred, context); + RangePredicate gtRange = extractor.visitBinaryPredicate(gtPred, context); + RangePredicate ltRange = extractor.visitBinaryPredicate(ltPred, context); + + Assertions.assertNotNull(eqRange); + Assertions.assertNotNull(gtRange); + Assertions.assertNotNull(ltRange); + } catch (Exception e) { + Assertions.fail("Predicate extraction should not throw exception: " + e.getMessage()); + } + } + + @Test + public void testInt32EdgeCasesInPredicates() { + // Test edge cases that could cause overflow in distance calculation + ColumnRefOperator columnRef = new ColumnRefOperator(1, Type.INT, "test_column", true); + + // Test with INT_MAX + ConstantOperator intMax = ConstantOperator.createInt(Integer.MAX_VALUE); + BinaryPredicateOperator maxPred = new BinaryPredicateOperator(BinaryType.EQ, columnRef, intMax); + + // Test with INT_MIN + ConstantOperator intMin = ConstantOperator.createInt(Integer.MIN_VALUE); + BinaryPredicateOperator minPred = new BinaryPredicateOperator(BinaryType.EQ, columnRef, intMin); + + // Test with the specific value from the issue + ConstantOperator issueValue = ConstantOperator.createInt(1234567890); + BinaryPredicateOperator issuePred = new BinaryPredicateOperator(BinaryType.EQ, columnRef, issueValue); + + PredicateExtractor extractor = new PredicateExtractor(); + PredicateExtractor.PredicateExtractorContext context = new PredicateExtractor.PredicateExtractorContext(); + + try { + RangePredicate maxRange = extractor.visitBinaryPredicate(maxPred, context); + RangePredicate minRange = extractor.visitBinaryPredicate(minPred, context); + RangePredicate issueRange = extractor.visitBinaryPredicate(issuePred, context); + + Assertions.assertNotNull(maxRange); + Assertions.assertNotNull(minRange); + Assertions.assertNotNull(issueRange); + } catch (Exception e) { + Assertions.fail("Edge case predicate extraction should not throw exception: " + e.getMessage()); + } + } +} \ No newline at end of file