This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 3a789b617f5 IGNITE-23178 SQL Calcite: Fix least restrictive type
priority (for DOUBLE and FLOAT) - Fixes #11520.
3a789b617f5 is described below
commit 3a789b617f50fc7c8277c395166ab8e8e7cba87f
Author: Vladimir Steshin <[email protected]>
AuthorDate: Tue Sep 24 17:43:23 2024 +0300
IGNITE-23178 SQL Calcite: Fix least restrictive type priority (for DOUBLE
and FLOAT) - Fixes #11520.
Signed-off-by: Aleksey Plekhanov <[email protected]>
---
.../query/calcite/type/IgniteTypeFactory.java | 13 +-
.../calcite/exec/NumericTypesPrecisionsTest.java | 202 +++++++++++++++++++++
.../ignite/testsuites/IgniteCalciteTestSuite.java | 3 +
3 files changed, 217 insertions(+), 1 deletion(-)
diff --git
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/type/IgniteTypeFactory.java
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/type/IgniteTypeFactory.java
index 744fea9c052..00de072af21 100644
---
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/type/IgniteTypeFactory.java
+++
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/type/IgniteTypeFactory.java
@@ -250,7 +250,18 @@ public class IgniteTypeFactory extends JavaTypeFactoryImpl
{
if (types.size() == 1 || allEquals(types))
return F.first(types);
- return super.leastRestrictive(types);
+ RelDataType res = super.leastRestrictive(types);
+
+ // Calcite compares approximate numerics by their precisions. While
FLOAT has the same precision as DOUBLE, the
+ // least restrictive may variate between them and issue FLOAT instead
of DOUBLE. DOUBLE is more preferable.
+ if (res != null && res.getSqlTypeName() == SqlTypeName.FLOAT &&
types.size() > 1) {
+ for (RelDataType type : types) {
+ if (type.getSqlTypeName() == SqlTypeName.DOUBLE &&
type.getPrecision() >= res.getPrecision())
+ return type;
+ }
+ }
+
+ return res;
}
/** {@inheritDoc} */
diff --git
a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/NumericTypesPrecisionsTest.java
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/NumericTypesPrecisionsTest.java
new file mode 100644
index 00000000000..e582e24b72a
--- /dev/null
+++
b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/exec/NumericTypesPrecisionsTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.processors.query.calcite.exec;
+
+import java.util.Arrays;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeSystem;
+import org.apache.calcite.sql.type.SqlTypeName;
+import
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import
org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeSystem;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/** Test for numeric types precisions. */
+public class NumericTypesPrecisionsTest {
+ /** */
+ private static final IgniteTypeFactory TYPE_FACTORY =
Commons.typeFactory();
+
+ /** */
+ private static final int STRING_PRECISION = 65536;
+
+ /** */
+ private static final int DECIMAL_PRECISION = 32767;
+
+ /** */
+ private static final int DECIMAL_SCALE = 32767;
+
+ /** */
+ private final RelDataTypeSystem typeSys = IgniteTypeSystem.INSTANCE;
+
+ /** */
+ private static final RelDataType TINYINT =
TYPE_FACTORY.createSqlType(SqlTypeName.TINYINT);
+
+ /** */
+ private static final RelDataType SMALLINT =
TYPE_FACTORY.createSqlType(SqlTypeName.SMALLINT);
+
+ /** */
+ private static final RelDataType INTEGER =
TYPE_FACTORY.createSqlType(SqlTypeName.INTEGER);
+
+ /** */
+ private static final RelDataType REAL =
TYPE_FACTORY.createSqlType(SqlTypeName.REAL);
+
+ /** */
+ private static final RelDataType FLOAT =
TYPE_FACTORY.createSqlType(SqlTypeName.FLOAT);
+
+ /** */
+ private static final RelDataType DOUBLE =
TYPE_FACTORY.createSqlType(SqlTypeName.DOUBLE);
+
+ /** */
+ private static final RelDataType DECIMAL =
TYPE_FACTORY.createSqlType(SqlTypeName.DECIMAL, 1000, 10);
+
+ /** */
+ private static final RelDataType BIGINT =
TYPE_FACTORY.createSqlType(SqlTypeName.BIGINT);
+
+ /** */
+ private static final RelDataType[] TEST_SUITE = new RelDataType[]
{TINYINT, SMALLINT, INTEGER, REAL, FLOAT, DOUBLE, DECIMAL, BIGINT};
+
+ /** */
+ @Test
+ public void testLeastRestrictiveTinyInt() {
+ RelDataType[] expected = new RelDataType[] {TINYINT, SMALLINT,
INTEGER, REAL, FLOAT, DOUBLE, DECIMAL, BIGINT};
+
+ doTestExpectedLeastRestrictive(TINYINT, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveSmallInt() {
+ RelDataType[] expected = new RelDataType[] {SMALLINT, SMALLINT,
INTEGER, REAL, FLOAT, DOUBLE, DECIMAL, BIGINT};
+
+ doTestExpectedLeastRestrictive(SMALLINT, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveInteger() {
+ RelDataType[] expected = new RelDataType[] {INTEGER, INTEGER, INTEGER,
REAL, FLOAT, DOUBLE, DECIMAL, BIGINT};
+
+ doTestExpectedLeastRestrictive(INTEGER, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveFloat() {
+ RelDataType[] expected = new RelDataType[] {FLOAT, FLOAT, FLOAT,
FLOAT, FLOAT, DOUBLE, DOUBLE, FLOAT};
+
+ doTestExpectedLeastRestrictive(FLOAT, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveDouble() {
+ RelDataType[] expected = new RelDataType[] {DOUBLE, DOUBLE, DOUBLE,
DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE};
+
+ doTestExpectedLeastRestrictive(DOUBLE, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveDecimal() {
+ RelDataType[] expected = new RelDataType[] {DECIMAL, DECIMAL, DECIMAL,
DOUBLE, DOUBLE, DOUBLE, DECIMAL, DECIMAL};
+
+ doTestExpectedLeastRestrictive(DECIMAL, expected);
+ }
+
+ /** */
+ @Test
+ public void testLeastRestrictiveBigInt() {
+ RelDataType[] expected = new RelDataType[] {BIGINT, BIGINT, BIGINT,
REAL, FLOAT, DOUBLE, DECIMAL, BIGINT};
+
+ doTestExpectedLeastRestrictive(BIGINT, expected);
+ }
+
+ /** This test is mostly for tracking possible chages with Calcite's
version updates. */
+ @Test
+ public void testMaxPrecision() {
+ assertEquals(STRING_PRECISION,
typeSys.getMaxPrecision(SqlTypeName.CHAR));
+ assertEquals(STRING_PRECISION,
typeSys.getMaxPrecision(SqlTypeName.VARCHAR));
+ assertEquals(STRING_PRECISION,
typeSys.getMaxPrecision(SqlTypeName.BINARY));
+ assertEquals(STRING_PRECISION,
typeSys.getMaxPrecision(SqlTypeName.VARBINARY));
+
+ assertEquals(3, typeSys.getMaxPrecision(SqlTypeName.TINYINT));
+ assertEquals(5, typeSys.getMaxPrecision(SqlTypeName.SMALLINT));
+ assertEquals(10, typeSys.getMaxPrecision(SqlTypeName.INTEGER));
+ assertEquals(19, typeSys.getMaxPrecision(SqlTypeName.BIGINT));
+ assertEquals(7, typeSys.getMaxPrecision(SqlTypeName.REAL));
+ assertEquals(15, typeSys.getMaxPrecision(SqlTypeName.FLOAT));
+ assertEquals(15, typeSys.getMaxPrecision(SqlTypeName.DOUBLE));
+ assertEquals(DECIMAL_PRECISION,
typeSys.getMaxPrecision(SqlTypeName.DECIMAL));
+
+ assertEquals(0, typeSys.getMaxPrecision(SqlTypeName.DATE));
+ assertEquals(3, typeSys.getMaxPrecision(SqlTypeName.TIME));
+ assertEquals(3,
typeSys.getMaxPrecision(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE));
+ assertEquals(3, typeSys.getMaxPrecision(SqlTypeName.TIMESTAMP));
+ assertEquals(3,
typeSys.getMaxPrecision(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE));
+ }
+
+ /** This test is mostly for tracking possible chages with Calcite's
version updates. */
+ @Test
+ public void testDefaultPrecision() {
+ assertEquals(1, typeSys.getDefaultPrecision(SqlTypeName.CHAR));
+ assertEquals(RelDataType.PRECISION_NOT_SPECIFIED,
typeSys.getDefaultPrecision(SqlTypeName.VARCHAR));
+ assertEquals(1, typeSys.getDefaultPrecision(SqlTypeName.BINARY));
+ assertEquals(RelDataType.PRECISION_NOT_SPECIFIED,
typeSys.getDefaultPrecision(SqlTypeName.VARBINARY));
+
+ assertEquals(3, typeSys.getDefaultPrecision(SqlTypeName.TINYINT));
+ assertEquals(5, typeSys.getDefaultPrecision(SqlTypeName.SMALLINT));
+ assertEquals(10, typeSys.getDefaultPrecision(SqlTypeName.INTEGER));
+ assertEquals(19, typeSys.getDefaultPrecision(SqlTypeName.BIGINT));
+ assertEquals(7, typeSys.getDefaultPrecision(SqlTypeName.REAL));
+ assertEquals(15, typeSys.getDefaultPrecision(SqlTypeName.FLOAT));
+ assertEquals(15, typeSys.getDefaultPrecision(SqlTypeName.DOUBLE));
+ assertEquals(DECIMAL_PRECISION,
typeSys.getDefaultPrecision(SqlTypeName.DECIMAL));
+
+ assertEquals(0, typeSys.getDefaultPrecision(SqlTypeName.DATE));
+ assertEquals(0, typeSys.getDefaultPrecision(SqlTypeName.TIME));
+ assertEquals(3,
typeSys.getDefaultPrecision(SqlTypeName.TIME_WITH_LOCAL_TIME_ZONE));
+ assertEquals(3, typeSys.getDefaultPrecision(SqlTypeName.TIMESTAMP));
+ assertEquals(0,
typeSys.getDefaultPrecision(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE));
+ }
+
+
+ /** This test is mostly for tracking possible chages with Calcite's
version updates. */
+ @Test
+ public void testMaxNumericPrecision() {
+ assertEquals(DECIMAL_PRECISION, typeSys.getMaxNumericPrecision());
+ }
+
+ /** This test is mostly for tracking possible chages with Calcite's
version updates. */
+ @Test
+ public void testMaxNumericScale() {
+ assertEquals(DECIMAL_SCALE, typeSys.getMaxNumericScale());
+ }
+
+ /** */
+ private static void doTestExpectedLeastRestrictive(RelDataType testType,
RelDataType[] expectedLeast) {
+ assert expectedLeast.length == TEST_SUITE.length;
+
+ for (int i = 0; i < TEST_SUITE.length; ++i) {
+ RelDataType actualType =
TYPE_FACTORY.leastRestrictive(Arrays.asList(testType, TEST_SUITE[i]));
+
+ assertEquals("leastRestrictive(" + testType + ", " + TEST_SUITE[i]
+ ")", expectedLeast[i], actualType);
+ }
+ }
+}
diff --git
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IgniteCalciteTestSuite.java
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IgniteCalciteTestSuite.java
index ed7ad797597..e71990733db 100644
---
a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IgniteCalciteTestSuite.java
+++
b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IgniteCalciteTestSuite.java
@@ -20,6 +20,7 @@ package org.apache.ignite.testsuites;
import org.apache.ignite.internal.processors.query.calcite.QueryCheckerTest;
import
org.apache.ignite.internal.processors.query.calcite.exec.ClosableIteratorsHolderTest;
import
org.apache.ignite.internal.processors.query.calcite.exec.LogicalRelImplementorTest;
+import
org.apache.ignite.internal.processors.query.calcite.exec.NumericTypesPrecisionsTest;
import
org.apache.ignite.internal.processors.query.calcite.exec.exp.IgniteSqlFunctionsTest;
import
org.apache.ignite.internal.processors.query.calcite.exec.tracker.MemoryTrackerTest;
import
org.apache.ignite.internal.processors.query.calcite.message.CalciteCommunicationMessageSerializationTest;
@@ -47,6 +48,8 @@ import org.junit.runners.Suite;
ScriptTestSuite.class,
CalciteCommunicationMessageSerializationTest.class,
+
+ NumericTypesPrecisionsTest.class,
})
public class IgniteCalciteTestSuite {
}