This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-26090 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit da965d43ac8277d57aeb01ec691f90b81787b22b Author: amashenkov <[email protected]> AuthorDate: Tue Sep 23 11:34:34 2025 +0300 add tests --- .../internal/sql/engine/ItFloatingPointTest.java | 190 +++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItFloatingPointTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItFloatingPointTest.java new file mode 100644 index 00000000000..064c0d5cb13 --- /dev/null +++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItFloatingPointTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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 org.apache.ignite.internal.sql.engine; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.stream.Collectors; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +/** Test floating point special values test. */ +public class ItFloatingPointTest extends BaseSqlMultiStatementTest { + @BeforeAll + void createTestTable() { + sqlScript("CREATE TABLE test (id INT PRIMARY KEY, f FLOAT, d DOUBLE);" + + "CREATE INDEX test_f_idx on test (f);" + + "CREATE INDEX test_d_idx on test (d);" + ); + + sql("INSERT INTO test VALUES (?, ?, ?)", 1, Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + sql("INSERT INTO test VALUES (?, ?, ?)", 2, Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); + sql("INSERT INTO test VALUES (?, ?, ?)", 3, Float.NaN, Double.NaN); + sql("INSERT INTO test VALUES (?, ?, ?)", 4, -1.0f, -1.0d); + sql("INSERT INTO test VALUES (?, ?, ?)", 5, 1.0f, 1.0d); + sql("INSERT INTO test VALUES (?, ?, ?)", 6, -0.0f, -0.0d); + sql("INSERT INTO test VALUES (?, ?, ?)", 7, +0.0f, +0.0d); + } + + @Override + protected int initialNodes() { + return 2; + } + + @Test + void testArithmetic() { + assertEquals(-0.0f, sql("SELECT -0.0::FLOAT").get(0).get(0)); + assertEquals(0.0f, sql("SELECT 0.0::FLOAT").get(0).get(0)); + + assertEquals(Float.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::FLOAT - 1").get(0).get(0)); + assertEquals(Float.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::FLOAT + 1").get(0).get(0)); + + assertEquals(Float.POSITIVE_INFINITY, sql("SELECT '+Infinity'::FLOAT - 1").get(0).get(0)); + assertEquals(Float.POSITIVE_INFINITY, sql("SELECT '+Infinity'::FLOAT + 1").get(0).get(0)); + + assertEquals(Float.NaN, sql("SELECT 'NaN'::FLOAT - 1").get(0).get(0)); + assertEquals(Float.NaN, sql("SELECT '-NaN'::FLOAT + 1").get(0).get(0)); + assertEquals(Float.NaN, sql("SELECT '-Infinity'::FLOAT + '+Infinity'::FLOAT").get(0).get(0)); + assertEquals(Float.NaN, sql("SELECT '-Infinity'::FLOAT / '+Infinity'::FLOAT").get(0).get(0)); + + assertEquals(Double.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::DOUBLE - 1").get(0).get(0)); + assertEquals(Double.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::DOUBLE + 1").get(0).get(0)); + + assertEquals(Double.POSITIVE_INFINITY, sql("SELECT '+Infinity'::DOUBLE - 1").get(0).get(0)); + assertEquals(Double.POSITIVE_INFINITY, sql("SELECT '+Infinity'::DOUBLE + 1").get(0).get(0)); + + assertEquals(Double.NaN, sql("SELECT 'NaN'::DOUBLE - 1").get(0).get(0)); + assertEquals(Double.NaN, sql("SELECT '-NaN'::DOUBLE + 1").get(0).get(0)); + assertEquals(Double.NaN, sql("SELECT '-Infinity'::DOUBLE + '+Infinity'::DOUBLE").get(0).get(0)); + assertEquals(Double.NaN, sql("SELECT '-Infinity'::DOUBLE / '+Infinity'::DOUBLE").get(0).get(0)); + } + + @Test + void testLiterals() { + assertEquals(-0.0f, sql("SELECT -0.0::FLOAT").get(0).get(0)); + assertEquals(0.0f, sql("SELECT 0.0::FLOAT").get(0).get(0)); + assertEquals(Float.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::FLOAT").get(0).get(0)); + assertEquals(Float.POSITIVE_INFINITY, sql("SELECT '+Infinity'::FLOAT").get(0).get(0)); + assertEquals(Float.NaN, sql("SELECT 'NaN'::FLOAT").get(0).get(0)); + assertEquals(Float.NaN, sql("SELECT -'NaN'::FLOAT").get(0).get(0)); + + assertEquals(-0.0d, sql("SELECT -0.0::DOUBLE").get(0).get(0)); + assertEquals(0.0d, sql("SELECT 0.0::DOUBLE").get(0).get(0)); + assertEquals(Double.NEGATIVE_INFINITY, sql("SELECT '-Infinity'::DOUBLE").get(0).get(0)); + assertEquals(Double.POSITIVE_INFINITY, sql("SELECT '+Infinity'::DOUBLE").get(0).get(0)); + assertEquals(Double.NaN, sql("SELECT 'NaN'::DOUBLE").get(0).get(0)); + assertEquals(Double.NaN, sql("SELECT -'NaN'::DOUBLE").get(0).get(0)); + } + + @ParameterizedTest + @ValueSource(floats = { + -0.0f, + 0.0f, + Float.NEGATIVE_INFINITY, + Float.POSITIVE_INFINITY, + Float.NaN + }) + void testParameters(float f) { + assertEquals(f, (float) sql("SELECT ?", f).get(0).get(0)); + } + + @ParameterizedTest + @ValueSource(doubles = { + -0.0d, + 0.0d, + Double.NEGATIVE_INFINITY, + Double.POSITIVE_INFINITY, + Double.NaN + }) + void testParameters(double f) { + assertEquals(f, (double) sql("SELECT ?", f).get(0).get(0)); + } + + @Test + void testOrderBySpecialValues() { + { + List<Float> values = sql("SELECT f FROM test ORDER BY f") + .stream().flatMap(List::stream).map(Float.class::cast).collect(Collectors.toList()); + + assertThat(values, Matchers.contains( + equalTo(Float.NEGATIVE_INFINITY), + equalTo(-1.0f), + equalTo(-0.0f), + equalTo(0.0f), + equalTo(1.0f), + equalTo(Float.POSITIVE_INFINITY), + equalTo(Float.NaN) // NaN first or last depending on DB + )); + } + { + List<Double> values = sql("SELECT d FROM test ORDER BY d") + .stream().flatMap(List::stream).map(Double.class::cast).collect(Collectors.toList()); + assertThat(values, Matchers.contains( + equalTo(Double.NEGATIVE_INFINITY), + equalTo(-1.0d), + equalTo(-0.0d), + equalTo(0.0d), + equalTo(1.0d), + equalTo(Double.POSITIVE_INFINITY), + equalTo(Double.NaN) // NaN first or last depending on DB + )); + } + } + + @Test + void testComparisons() { + assertEquals(1L, sql("SELECT COUNT(*) FROM test WHERE f = '-Infinity'::FLOAT").get(0).get(0)); + assertEquals(1L, sql("SELECT COUNT(*) FROM test WHERE f = '-Infinity'::DOUBLE").get(0).get(0)); + + assertEquals(1L, sql("SELECT COUNT(*) FROM test WHERE f = '+Infinity'::FLOAT").get(0).get(0)); + assertEquals(1L, sql("SELECT COUNT(*) FROM test WHERE f = '+Infinity'::DOUBLE").get(0).get(0)); + + assertEquals(0L, sql("SELECT COUNT(*) FROM test WHERE f = 'NaN'::FLOAT").get(0).get(0)); // NaN never equals + assertEquals(0L, sql("SELECT COUNT(*) FROM test WHERE f = 'NaN'::DOUBLE").get(0).get(0)); // NaN never equals + + assertEquals(2L, sql("SELECT COUNT(*) FROM test WHERE f > 0").get(0).get(0)); // 1.0, +Infinity + assertEquals(2L, sql("SELECT COUNT(*) FROM test WHERE f < 0").get(0).get(0)); // -Infinity, -1,0 + + assertEquals(5L, sql("SELECT COUNT(*) FROM test " + + "WHERE f IS DISTINCT FROM '+Infinity'::FLOAT AND d IS DISTINCT FROM '-Infinity'::FLOAT").get(0).get(0)); // NaN, 1.0, -1,0 + assertEquals(5L, sql("SELECT COUNT(*) FROM test " + + "WHERE f IS DISTINCT FROM '+Infinity'::DOUBLE AND d IS DISTINCT FROM '-Infinity'::DOUBLE").get(0).get(0)); + + // NaN not equal to NaN + assertEquals(7L, sql("SELECT COUNT(*) FROM test WHERE f IS DISTINCT FROM 'NaN'::FLOAT").get(0).get(0)); + assertEquals(7L, sql("SELECT COUNT(*) FROM test WHERE d IS DISTINCT FROM 'NaN'::DOUBLE").get(0).get(0)); + } + + @Test + void testAggregations() { + List<List<Object>> minRows = sql("SELECT MIN(f), MIN(d) FROM test"); + List<List<Object>> maxRows = sql("SELECT MAX(f), MAX(d) FROM test"); + List<List<Object>> avgRows = sql("SELECT AVG(f), AVG(d) FROM test"); + + assertThat(minRows.get(0), contains(Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY)); + assertThat(maxRows.get(0), contains(Float.NaN, Double.NaN)); + assertThat(avgRows.get(0), contains(Double.NaN, Double.NaN)); + } +}
