Skip to content

Commit

Permalink
Allow changing field type in records wrapped in an array
Browse files Browse the repository at this point in the history
  • Loading branch information
losipiuk committed Jun 3, 2024
1 parent c8ee63f commit 442866f
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package io.trino.execution;

import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Inject;
import io.trino.Session;
Expand All @@ -25,6 +26,7 @@
import io.trino.spi.TrinoException;
import io.trino.spi.connector.ColumnHandle;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.type.ArrayType;
import io.trino.spi.type.RowType;
import io.trino.spi.type.Type;
import io.trino.spi.type.TypeManager;
Expand Down Expand Up @@ -128,6 +130,11 @@ else if (metadata.isView(session, qualifiedObjectName)) {
throw semanticException(AMBIGUOUS_NAME, statement, "Field path %s within %s is ambiguous", fieldPath, columnMetadata.getType());
}
currentType = getOnlyElement(candidates).getType();

if (getOnlyElement(candidates).getName().isEmpty() && i == fieldPath.size() - 1) {
// field path ends up on 'element' unwrapping array
throw semanticException(COLUMN_NOT_FOUND, statement, "Field path %s does not point to row field", fieldPath);
}
}

checkState(fieldPath.size() >= 2, "fieldPath size must be >= 2: %s", fieldPath);
Expand All @@ -139,6 +146,13 @@ else if (metadata.isView(session, qualifiedObjectName)) {

private static List<RowType.Field> getCandidates(Type type, String fieldName)
{
if (type instanceof ArrayType arrayType) {
if (!fieldName.equals("element")) {
throw new TrinoException(NOT_SUPPORTED, "ARRAY type should be denoted by 'element' in the path; found '%s'".formatted(fieldName));
}
// return nameless Field to denote unwrapping of container
return ImmutableList.of(RowType.field(arrayType.getElementType()));
}
if (!(type instanceof RowType rowType)) {
throw new TrinoException(NOT_SUPPORTED, "Unsupported type: " + type);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,19 @@ public void setFieldType(ConnectorSession session, ConnectorTableHandle tableHan
NestedField parent = icebergTable.schema().caseInsensitiveFindField(parentPath);

String caseSensitiveParentName = icebergTable.schema().findColumnName(parent.fieldId());
NestedField field = parent.type().asStructType().caseInsensitiveField(getLast(fieldPath));

Types.StructType structType;
if (parent.type().isListType()) {
// list(struct...)
structType = parent.type().asListType().elementType().asStructType();
caseSensitiveParentName += ".element";
}
else {
// just struct
structType = parent.type().asStructType();
}
NestedField field = structType.caseInsensitiveField(getLast(fieldPath));

// TODO: Add support for changing non-primitive field type
if (!field.type().isPrimitiveType()) {
throw new TrinoException(NOT_SUPPORTED, "Iceberg doesn't support changing field type from non-primitive types");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ROW_TYPE;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_SET_COLUMN_TYPE;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_SET_FIELD_TYPE;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_SET_FIELD_TYPE_IN_ARRAY;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_TOPN_PUSHDOWN;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_TRUNCATE;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_UPDATE;
Expand Down Expand Up @@ -3219,6 +3220,53 @@ public void testSetFieldOutOfRangeType()
}
}

@Test
public void testSetFieldTypeInArray()
{
skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE_WITH_DATA) && hasBehavior(SUPPORTS_ARRAY) && hasBehavior(SUPPORTS_ROW_TYPE));

if (!hasBehavior(SUPPORTS_SET_FIELD_TYPE_IN_ARRAY)) {
try (TestTable table = new TestTable(getQueryRunner()::execute, "test_set_field_type_in_array_", "(col array(row(field int)))")) {
assertQueryFails(
"ALTER TABLE " + table.getName() + " ALTER COLUMN col.element.field SET DATA TYPE bigint",
".*does not support.*");
}
return;
}

try (TestTable table = new TestTable(getQueryRunner()::execute, "test_set_field_type_in_array_", "AS SELECT CAST(array[row(123)] AS array(row(field integer))) AS col")) {
assertThat(getColumnType(table.getName(), "col")).isEqualTo("array(row(field integer))");

assertUpdate("ALTER TABLE " + table.getName() + " ALTER COLUMN col.element.field SET DATA TYPE bigint");

assertThat(getColumnType(table.getName(), "col")).isEqualTo("array(row(field bigint))");
assertThat(query("SELECT * FROM " + table.getName()))
.skippingTypesCheck()
.matches("SELECT array[row(bigint '123')]");
}
}

@Test
public void testSetFieldTypeInNestedArray()
{
skipTestUnless(hasBehavior(SUPPORTS_SET_FIELD_TYPE_IN_ARRAY) && hasBehavior(SUPPORTS_CREATE_TABLE_WITH_DATA) && hasBehavior(SUPPORTS_ARRAY) && hasBehavior(SUPPORTS_ROW_TYPE));

try (TestTable table = new TestTable(getQueryRunner()::execute, "test_set_field_type_in_nested_array_", "AS SELECT CAST(array[array[row(array[row(123)])]] AS array(array(row(field array(row(a integer)))))) AS col")) {
assertThat(getColumnType(table.getName(), "col")).isEqualTo("array(array(row(field array(row(a integer)))))");

assertUpdate("ALTER TABLE " + table.getName() + " ALTER COLUMN col.element.element.field.element.a SET DATA TYPE bigint");

assertThat(getColumnType(table.getName(), "col")).isEqualTo("array(array(row(field array(row(a bigint)))))");
assertThat(query("SELECT * FROM " + table.getName()))
.skippingTypesCheck()
.matches("SELECT array[array[row(array[row(bigint '123')])]]");

assertQueryFails(
"ALTER TABLE " + table.getName() + " ALTER COLUMN col.element.element SET DATA TYPE bigint",
"\\Qline 1:1: Field path [col, element, element] does not point to row field");
}
}

protected void verifySetFieldTypeFailurePermissible(Throwable e)
{
throw new AssertionError("Unexpected set field type failure", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public enum TestingConnectorBehavior
SUPPORTS_RENAME_FIELD(fallback -> fallback.test(SUPPORTS_RENAME_COLUMN) && fallback.test(SUPPORTS_ROW_TYPE)),
SUPPORTS_SET_COLUMN_TYPE,
SUPPORTS_SET_FIELD_TYPE(fallback -> fallback.test(SUPPORTS_SET_COLUMN_TYPE) && fallback.test(SUPPORTS_ROW_TYPE)),
SUPPORTS_SET_FIELD_TYPE_IN_ARRAY(fallback -> fallback.test(SUPPORTS_SET_FIELD_TYPE) && fallback.test(SUPPORTS_ADD_FIELD_IN_ARRAY)),

SUPPORTS_COMMENT_ON_TABLE,
SUPPORTS_COMMENT_ON_COLUMN(SUPPORTS_COMMENT_ON_TABLE),
Expand Down

0 comments on commit 442866f

Please sign in to comment.