diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java index 1dfc604713c..6608d151e5a 100644 --- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java +++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItDataTypesTest.java @@ -50,6 +50,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; /** @@ -129,6 +130,34 @@ public void exactWithApproxComparison() { assertQuery("SELECT '1.1'::float > 2").returns(false).check(); } + @ParameterizedTest + @CsvSource({"FLOAT", "REAL", "DOUBLE"}) + public void nonFiniteNumerics(String type) { + Number positiveInfinity; + Number negativeInfinity; + Number nan; + + if ("DOUBLE".equals(type)) { + positiveInfinity = Double.POSITIVE_INFINITY; + negativeInfinity = Double.NEGATIVE_INFINITY; + nan = Double.NaN; + } else { + positiveInfinity = Float.POSITIVE_INFINITY; + negativeInfinity = Float.NEGATIVE_INFINITY; + nan = Float.NaN; + } + + assertQuery(format("select CAST('+Infinity' AS {})", type)).returns(positiveInfinity).check(); + assertQuery(format("select CAST('Infinity' AS {})", type)).returns(positiveInfinity).check(); + assertQuery(format("select CAST('-Infinity' AS {})", type)).returns(negativeInfinity).check(); + assertQuery(format("select CAST('NaN' AS {})", type)).returns(nan).check(); + + assertQuery(format("SELECT * FROM (VALUES(0)) AS t(k) WHERE k < CAST('+Infinity' AS REAL)", type)).returns(0).check(); + assertQuery(format("SELECT * FROM (VALUES(0)) AS t(k) WHERE k < CAST('Infinity' AS REAL)", type)).returns(0).check(); + assertQuery(format("SELECT * FROM (VALUES(0)) AS t(k) WHERE k > CAST('-Infinity' AS REAL)", type)).returns(0).check(); + assertQuery(format("SELECT * FROM (VALUES(0)) AS t(k) WHERE k <> CAST('NaN' AS REAL)", type)).returns(0).check(); + } + @WithSystemProperty(key = "IMPLICIT_PK_ENABLED", value = "true") @ParameterizedTest() @MethodSource("exactDecimalTypes") diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java index d4bc44a203e..6e76d19332e 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/externalize/RelJson.java @@ -881,12 +881,6 @@ RexNode toRex(RelInput relInput, Object o) { literal = new BigDecimal(((Number) literal).longValue()); } - // Stub, it need to be fixed https://issues.apache.org/jira/browse/IGNITE-23873 - if (type.getSqlTypeName() == SqlTypeName.DOUBLE && literal instanceof String - && Double.isNaN(Double.parseDouble(literal.toString()))) { - literal = Double.NaN; - } - if (literal instanceof BigInteger) { // If the literal is a BigInteger, RexBuilder assumes it represents a long value // within the valid range and converts it without checking the bounds. If the diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java index 4d9ec1ba9fc..c109266ee7b 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/rex/IgniteRexBuilder.java @@ -55,27 +55,37 @@ public RexNode makeLiteral(@Nullable Object value, RelDataType type, boolean all // IgniteCustomType: Not comparable types are not supported. assert value instanceof Comparable : "Not comparable IgniteCustomType:" + type + ". value: " + value; return makeLiteral((Comparable) value, type, type.getSqlTypeName()); - } else if (value != null && type.getSqlTypeName() == SqlTypeName.CHAR) { - if (type.isNullable()) { - RelDataType typeNotNull = - typeFactory.createTypeWithNullability(type, false); - if (allowCast) { - RexNode literalNotNull = makeLiteral(value, typeNotNull, allowCast); - return makeAbstractCast(type, literalNotNull, false); + } + + if (value != null) { + if (type.getSqlTypeName() == SqlTypeName.CHAR) { + if (type.isNullable()) { + RelDataType typeNotNull = + typeFactory.createTypeWithNullability(type, false); + if (allowCast) { + RexNode literalNotNull = makeLiteral(value, typeNotNull, allowCast); + return makeAbstractCast(type, literalNotNull, false); + } } - } - NlsString string; - if (value instanceof NlsString) { - string = (NlsString) value; - } else { - assert type.getCharset() != null : type + ".getCharset() must not be null"; - string = new NlsString((String) value, type.getCharset().name(), type.getCollation()); - } + NlsString string; + if (value instanceof NlsString) { + string = (NlsString) value; + } else { + assert type.getCharset() != null : type + ".getCharset() must not be null"; + string = new NlsString((String) value, type.getCharset().name(), type.getCollation()); + } - return makeCharLiteral(string); - } else { - return super.makeLiteral(value, type, allowCast, trim); + return makeCharLiteral(string); + } else if (value instanceof String) { + if (type.getSqlTypeName() == SqlTypeName.DOUBLE) { + value = Double.parseDouble((String) value); + } else if (type.getSqlTypeName() == SqlTypeName.REAL || type.getSqlTypeName() == SqlTypeName.FLOAT) { + value = Float.parseFloat((String) value); + } + } } + + return super.makeLiteral(value, type, allowCast, trim); } } diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java index 2c87f9ab4ed..2f7d0bea09f 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMath.java @@ -444,6 +444,11 @@ public static float convertToFloatExact(Number x) { return value.floatValue(); } else { double v = x.doubleValue(); + + if (!Double.isFinite(v)) { + return x.floatValue(); + } + if (v > UPPER_FLOAT_DOUBLE || v < LOWER_FLOAT_DOUBLE) { throw outOfRangeForTypeException(SqlTypeName.REAL); }