Skip to content

Commit

Permalink
[CALCITE-6764] Field access from a nullable ROW should be nullable (p…
Browse files Browse the repository at this point in the history
…art 2)

Signed-off-by: Mihai Budiu <[email protected]>
  • Loading branch information
mihaibudiu committed Jan 13, 2025
1 parent 5f767dd commit 8cddd87
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7081,7 +7081,12 @@ private class DeriveTypeVisitor implements SqlVisitor<RelDataType> {
throw newValidationError(id.getComponent(i),
RESOURCE.unknownField(name));
}
boolean recordIsNullable = type.isNullable();
type = field.getType();
if (recordIsNullable) {
// If parent record is nullable, field must also be nullable.
type = getTypeFactory().createTypeWithNullability(type, true);
}
}
type =
SqlTypeUtil.addCharsetAndCollation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,29 +87,13 @@ class TableInRootSchemaTest {
connection.close();
}

/**
* Helper class for the test for [CALCITE-6764] below.
*/
private static class RowTable extends AbstractQueryableTable {
protected RowTable() {
/** Represents a table with no data. An abstract base class,
* derived classes need to define the schema. */
private abstract static class EmptyTable extends AbstractQueryableTable {
protected EmptyTable() {
super(Object[].class);
}

@Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
final PairList<String, RelDataType> columnDesc = PairList.withCapacity(1);
// Schema contains a column whose type is MAP<VARCHAR, ROW(VARCHAR)>, but
// the ROW type can be nullable.
final RelDataType colType =
typeFactory.createMapType(typeFactory.createSqlType(SqlTypeName.VARCHAR),
new RelRecordType(
StructKind.PEEK_FIELDS,
ImmutableList.of(
new RelDataTypeFieldImpl("K", 0,
typeFactory.createSqlType(SqlTypeName.VARCHAR))), true));
columnDesc.add("P", colType);
return typeFactory.createStructType(columnDesc);
}

@Override public <T> Queryable<T> asQueryable(
QueryProvider queryProvider, SchemaPlus schema, String tableName) {
return new AbstractTableQueryable<T>(queryProvider, schema, this,
Expand All @@ -134,6 +118,51 @@ protected RowTable() {
}
}

/** Helper class for the test for [CALCITE-6764] below. */
private static class RowTable extends EmptyTable {
protected RowTable() {
super();
}

@Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
final PairList<String, RelDataType> columnDesc = PairList.withCapacity(1);
// Schema contains a column whose type is MAP<VARCHAR, ROW(VARCHAR)>, but
// the ROW type can be nullable. This can conceivably be created by a
// declaration such as
// CREATE TABLE T(p MAP<VARCHAR, ROW(k VARCHAR)>);
final RelDataType colType =
typeFactory.createMapType(typeFactory.createSqlType(SqlTypeName.VARCHAR),
new RelRecordType(
StructKind.PEEK_FIELDS,
ImmutableList.of(
new RelDataTypeFieldImpl("K", 0,
typeFactory.createSqlType(SqlTypeName.VARCHAR))), true));
columnDesc.add("P", colType);
return typeFactory.createStructType(columnDesc);
}
}

/** Helper class for the test for [CALCITE-6764] below. */
private static class RowTable2 extends EmptyTable {
protected RowTable2() {
super();
}

@Override public RelDataType getRowType(RelDataTypeFactory typeFactory) {
final PairList<String, RelDataType> columnDesc = PairList.withCapacity(1);
// This table can conceivably be created by a declaration such as
// CREATE TABLE T(p ROW(k VARCHAR) NULL);
final RelDataType colType =
new RelRecordType(
StructKind.PEEK_FIELDS, ImmutableList.of(
new RelDataTypeFieldImpl(
"K", 0, typeFactory.createSqlType(SqlTypeName.VARCHAR))),
true);
columnDesc.add("P", colType);
return typeFactory.createStructType(columnDesc);
}
}

/** Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-6764">[CALCITE-6764]
* Field access from a nullable ROW should be nullable</a>. */
@Test void testNullableValue() throws Exception {
Expand All @@ -146,4 +175,17 @@ protected RowTable() {
statement.close();
connection.close();
}

/** Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-6764">[CALCITE-6764]
* Field access from a nullable ROW should be nullable</a>. */
@Test void testNullableValue2() throws Exception {
Connection connection = DriverManager.getConnection("jdbc:calcite:");
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
calciteConnection.getRootSchema().add("T", new RowTable2());
Statement statement = calciteConnection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT t.p.k FROM T");
resultSet.close();
statement.close();
connection.close();
}
}

0 comments on commit 8cddd87

Please sign in to comment.