You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by sn...@apache.org on 2021/05/16 15:08:59 UTC
[calcite] branch master updated: [CALCITE-4603] Least restrictive
for collections of collections
This is an automated email from the ASF dual-hosted git repository.
snuyanzin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/master by this push:
new 61f8faf [CALCITE-4603] Least restrictive for collections of collections
61f8faf is described below
commit 61f8faf590aa2b832d8e11b7fa24fd1bd0c4a7a9
Author: snuyanzin <sn...@gmail.com>
AuthorDate: Wed May 12 00:07:05 2021 +0200
[CALCITE-4603] Least restrictive for collections of collections
Close apache/calcite#2413
---
.../calcite/rel/type/RelDataTypeFactoryImpl.java | 49 ++++++++++++++++
.../calcite/sql/type/SqlTypeFactoryImpl.java | 10 +++-
.../calcite/sql/type/SqlTypeFactoryTest.java | 66 ++++++++++++++++++++++
.../apache/calcite/sql/type/SqlTypeFixture.java | 16 ++++++
4 files changed, 140 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
index 41a9f68..818dd60 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java
@@ -18,7 +18,10 @@ package org.apache.calcite.rel.type;
import org.apache.calcite.linq4j.tree.Primitive;
import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.type.ArraySqlType;
import org.apache.calcite.sql.type.JavaToSqlTypeConversionRules;
+import org.apache.calcite.sql.type.MapSqlType;
+import org.apache.calcite.sql.type.MultisetSqlType;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.type.SqlTypeUtil;
@@ -257,6 +260,52 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
return createTypeWithNullability(builder.build(), isNullable);
}
+ protected @Nullable RelDataType leastRestrictiveArrayMultisetType(
+ final List<RelDataType> types, SqlTypeName sqlTypeName) {
+ assert sqlTypeName == SqlTypeName.ARRAY || sqlTypeName == SqlTypeName.MULTISET;
+ boolean isNullable = false;
+ for (RelDataType type: types) {
+ if (type.getComponentType() == null) {
+ return null;
+ }
+ isNullable |= type.isNullable();
+ }
+ final RelDataType type = leastRestrictive(
+ Util.transform(types,
+ t -> t instanceof ArraySqlType
+ ? ((ArraySqlType) t).getComponentType()
+ : ((MultisetSqlType) t).getComponentType()));
+ if (type == null) {
+ return null;
+ }
+ return sqlTypeName == SqlTypeName.ARRAY
+ ? new ArraySqlType(type, isNullable)
+ : new MultisetSqlType(type, isNullable);
+ }
+
+ protected @Nullable RelDataType leastRestrictiveMapType(
+ final List<RelDataType> types, SqlTypeName sqlTypeName) {
+ assert sqlTypeName == SqlTypeName.MAP;
+ boolean isNullable = false;
+ for (RelDataType type: types) {
+ if (!(type instanceof MapSqlType)) {
+ return null;
+ }
+ isNullable |= type.isNullable();
+ }
+ final RelDataType keyType = leastRestrictive(
+ Util.transform(types, t -> ((MapSqlType) t).getKeyType()));
+ if (keyType == null) {
+ return null;
+ }
+ final RelDataType valueType = leastRestrictive(
+ Util.transform(types, t -> ((MapSqlType) t).getValueType()));
+ if (valueType == null) {
+ return null;
+ }
+ return new MapSqlType(keyType, valueType, isNullable);
+ }
+
// copy a non-record type, setting nullability
private RelDataType copySimpleType(
RelDataType type,
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
index e20dd59..6fd58e6 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
@@ -287,9 +287,17 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
if (resultType == null) {
resultType = type;
- if (resultType.getSqlTypeName() == SqlTypeName.ROW) {
+ SqlTypeName sqlTypeName = resultType.getSqlTypeName();
+ if (sqlTypeName == SqlTypeName.ROW) {
return leastRestrictiveStructuredType(types);
}
+ if (sqlTypeName == SqlTypeName.ARRAY
+ || sqlTypeName == SqlTypeName.MULTISET) {
+ return leastRestrictiveArrayMultisetType(types, sqlTypeName);
+ }
+ if (sqlTypeName == SqlTypeName.MAP) {
+ return leastRestrictiveMapType(types, sqlTypeName);
+ }
}
RelDataTypeFamily resultFamily = resultType.getFamily();
diff --git a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFactoryTest.java b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFactoryTest.java
index f1c63fd..b0f9d56 100644
--- a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFactoryTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFactoryTest.java
@@ -34,6 +34,7 @@ import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -83,6 +84,71 @@ class SqlTypeFactoryTest {
assertThat(leastRestrictive.isNullable(), is(true));
}
+ @Test void testLeastRestrictiveForImpossibleWithArray() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.arraySqlChar10, f.sqlChar));
+ assertNull(leastRestrictive);
+ }
+
+ @Test void testLeastRestrictiveForArrays() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.arraySqlChar10, f.arraySqlChar1));
+ assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.ARRAY));
+ assertThat(leastRestrictive.isNullable(), is(false));
+ assertThat(leastRestrictive.getComponentType().getPrecision(), is(10));
+ }
+
+ @Test void testLeastRestrictiveForMultisets() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.multisetSqlChar10Nullable, f.multisetSqlChar1));
+ assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.MULTISET));
+ assertThat(leastRestrictive.isNullable(), is(true));
+ assertThat(leastRestrictive.getComponentType().getPrecision(), is(10));
+ }
+
+ @Test void testLeastRestrictiveForMultisetsAndArrays() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.multisetSqlChar10Nullable, f.arraySqlChar1));
+ assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.MULTISET));
+ assertThat(leastRestrictive.isNullable(), is(true));
+ assertThat(leastRestrictive.getComponentType().getPrecision(), is(10));
+ }
+
+ @Test void testLeastRestrictiveForImpossibleWithMultisets() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.multisetSqlChar10Nullable, f.mapSqlChar1));
+ assertNull(leastRestrictive);
+ }
+
+ @Test void testLeastRestrictiveForMaps() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.mapSqlChar10Nullable, f.mapSqlChar1));
+ assertThat(leastRestrictive.getSqlTypeName(), is(SqlTypeName.MAP));
+ assertThat(leastRestrictive.isNullable(), is(true));
+ assertThat(leastRestrictive.getKeyType().getPrecision(), is(10));
+ assertThat(leastRestrictive.getValueType().getPrecision(), is(10));
+ }
+
+ @Test void testLeastRestrictiveForImpossibleWithMaps() {
+ SqlTypeFixture f = new SqlTypeFixture();
+ RelDataType leastRestrictive =
+ f.typeFactory.leastRestrictive(
+ Lists.newArrayList(f.mapSqlChar10Nullable, f.arraySqlChar1));
+ assertNull(leastRestrictive);
+ }
+
/** Unit test for {@link SqlTypeUtil#comparePrecision(int, int)}
* and {@link SqlTypeUtil#maxPrecision(int, int)}. */
@Test void testMaxPrecision() {
diff --git a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFixture.java b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFixture.java
index fe47de5..6827024 100644
--- a/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFixture.java
+++ b/core/src/test/java/org/apache/calcite/sql/type/SqlTypeFixture.java
@@ -78,4 +78,20 @@ class SqlTypeFixture {
typeFactory.createMapType(sqlInt, sqlInt), false);
final RelDataType mapOfIntNullable = typeFactory.createTypeWithNullability(
typeFactory.createMapType(sqlInt, sqlInt), true);
+ final RelDataType sqlChar1 = typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.CHAR, 1), false);
+ final RelDataType sqlChar10 = typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(SqlTypeName.CHAR, 10), false);
+ final RelDataType arraySqlChar10 = typeFactory.createTypeWithNullability(
+ typeFactory.createArrayType(sqlChar10, -1), false);
+ final RelDataType arraySqlChar1 = typeFactory.createTypeWithNullability(
+ typeFactory.createArrayType(sqlChar1, -1), false);
+ final RelDataType multisetSqlChar10Nullable = typeFactory.createTypeWithNullability(
+ typeFactory.createMultisetType(sqlChar10, -1), true);
+ final RelDataType multisetSqlChar1 = typeFactory.createTypeWithNullability(
+ typeFactory.createMultisetType(sqlChar1, -1), false);
+ final RelDataType mapSqlChar10Nullable = typeFactory.createTypeWithNullability(
+ typeFactory.createMapType(sqlChar10, sqlChar10), true);
+ final RelDataType mapSqlChar1 = typeFactory.createTypeWithNullability(
+ typeFactory.createMapType(sqlChar1, sqlChar1), false);
}