This is an automated email from the ASF dual-hosted git repository.
hongze 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 37002c1 [CALCITE-3029] Java-oriented field type is wrongly forced to
be NOT NULL after being converted to SQL-oriented
37002c1 is described below
commit 37002c1399cea1464b5d53c0fc4e5ec90f831f1b
Author: Hongze Zhang <[email protected]>
AuthorDate: Sun Apr 28 18:21:00 2019 +0800
[CALCITE-3029] Java-oriented field type is wrongly forced to be NOT NULL
after being converted to SQL-oriented
---
.../apache/calcite/jdbc/JavaTypeFactoryImpl.java | 32 +++++++++-------------
.../apache/calcite/jdbc/JavaTypeFactoryTest.java | 16 +++++++++++
.../java/org/apache/calcite/tools/PlannerTest.java | 19 +++++++++++++
3 files changed, 48 insertions(+), 19 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
index d51de1c..40e462a 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
@@ -37,8 +37,6 @@ import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.util.Pair;
import org.apache.calcite.util.Util;
-import com.google.common.collect.Lists;
-
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
@@ -49,6 +47,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.stream.Collectors;
/**
* Implementation of {@link JavaTypeFactory}.
@@ -240,26 +239,21 @@ public class JavaTypeFactoryImpl
/** Converts a type in Java format to a SQL-oriented type. */
public static RelDataType toSql(final RelDataTypeFactory typeFactory,
RelDataType type) {
- return toSql(typeFactory, type, true);
- }
-
- private static RelDataType toSql(final RelDataTypeFactory typeFactory,
- RelDataType type, boolean mustSetNullability) {
- RelDataType sqlType = type;
if (type instanceof RelRecordType) {
- // We do not need to change the nullability of the nested fields,
- // since it can be overridden by the existing implementation of
createTypeWithNullability
- // when we treat the nullability of the root struct type.
- sqlType = typeFactory.createStructType(
- Lists.transform(type.getFieldList(),
- field -> toSql(typeFactory, field.getType(), false)),
- type.getFieldNames());
+ return typeFactory.createTypeWithNullability(
+ typeFactory.createStructType(
+ type.getFieldList()
+ .stream()
+ .map(field -> toSql(typeFactory, field.getType()))
+ .collect(Collectors.toList()),
+ type.getFieldNames()),
+ type.isNullable());
} else if (type instanceof JavaType) {
- sqlType = typeFactory.createSqlType(type.getSqlTypeName());
+ return typeFactory.createTypeWithNullability(
+ typeFactory.createSqlType(type.getSqlTypeName()),
+ type.isNullable());
}
- return mustSetNullability
- ? typeFactory.createTypeWithNullability(sqlType, type.isNullable())
- : sqlType;
+ return type;
}
public Type createSyntheticType(List<Type> types) {
diff --git
a/core/src/test/java/org/apache/calcite/jdbc/JavaTypeFactoryTest.java
b/core/src/test/java/org/apache/calcite/jdbc/JavaTypeFactoryTest.java
index cd0ba7a..0980e1d 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/JavaTypeFactoryTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/JavaTypeFactoryTest.java
@@ -18,6 +18,7 @@ package org.apache.calcite.jdbc;
import org.apache.calcite.linq4j.tree.Types;
import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.test.SqlTests;
import org.apache.calcite.sql.type.SqlTypeName;
import com.google.common.collect.ImmutableList;
@@ -73,6 +74,21 @@ public final class JavaTypeFactoryTest {
assertRecordType(TYPE_FACTORY.getJavaClass(structWithTwoFields));
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-3029">[CALCITE-3029]
+ * Java-oriented field type is wrongly forced to be NOT NULL after being
converted to
+ * SQL-oriented</a>. */
+ @Test public void testFieldNullabilityAfterConvertingToSqlStructType() {
+ RelDataType javaStructType = TYPE_FACTORY.createStructType(
+ ImmutableList.of(
+ TYPE_FACTORY.createJavaType(Integer.class),
+ TYPE_FACTORY.createJavaType(int.class)),
+ ImmutableList.of("a", "b"));
+ RelDataType sqlStructType = TYPE_FACTORY.toSql(javaStructType);
+ assertEquals("RecordType(INTEGER a, INTEGER NOT NULL b) NOT NULL",
+ SqlTests.getTypeString(sqlStructType));
+ }
+
private void assertRecordType(Type actual) {
String errorMessage =
"Type {" + actual.getTypeName() + "} is not a subtype of
Types.RecordType";
diff --git a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
index 7d73397..b578e9d 100644
--- a/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
+++ b/core/src/test/java/org/apache/calcite/tools/PlannerTest.java
@@ -70,6 +70,7 @@ import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.test.SqlTests;
import org.apache.calcite.sql.type.OperandTypes;
import org.apache.calcite.sql.type.ReturnTypes;
import org.apache.calcite.sql.type.SqlTypeName;
@@ -98,6 +99,7 @@ import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@@ -703,6 +705,23 @@ public class PlannerTest {
+ " EnumerableTableScan(table=[[hr, emps]])\n"));
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-3029">[CALCITE-3029]
+ * Java-oriented field type is wrongly forced to be NOT NULL after being
converted to
+ * SQL-oriented</a>. */
+ @Test public void testInsertSourceRelTypeWithNullValues() throws Exception {
+ Planner planner = getPlanner(null, Programs.standard());
+ SqlNode parse = planner.parse(
+ "insert into \"emps\" values(1, 1, null, 1, 1)");
+ SqlNode validate = planner.validate(parse);
+ RelNode convert = planner.rel(validate).rel;
+ RelDataType insertSourceType = convert.getInput(0).getRowType();
+ String typeString = SqlTests.getTypeString(insertSourceType);
+ assertEquals("RecordType(INTEGER NOT NULL empid, INTEGER NOT NULL deptno,
VARCHAR name, "
+ + "REAL NOT NULL salary, INTEGER commission) NOT NULL",
typeString);
+ }
+
+
/** Unit test that parses, validates, converts and plans. Planner is
* provided with a list of RelTraitDefs to register. */
@Test public void testPlanWithExplicitTraitDefs() throws Exception {