Skip to content

Commit

Permalink
Support FIRST and AFTER clause when adding a new column in Iceberg
Browse files Browse the repository at this point in the history
  • Loading branch information
ebyhr committed Jan 17, 2025
1 parent 3f758b0 commit d949877
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
{
return switch (connectorBehavior) {
case SUPPORTS_UPDATE -> true;
case SUPPORTS_CREATE_MATERIALIZED_VIEW,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
SUPPORTS_CREATE_VIEW,
SUPPORTS_MERGE,
SUPPORTS_PREDICATE_EXPRESSION_PUSHDOWN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
return switch (connectorBehavior) {
case SUPPORTS_CREATE_OR_REPLACE_TABLE,
SUPPORTS_REPORTING_WRITTEN_BYTES -> true;
case SUPPORTS_ADD_FIELD,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_ADD_FIELD,
SUPPORTS_AGGREGATION_PUSHDOWN,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
SUPPORTS_DROP_FIELD,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
return switch (connectorBehavior) {
case SUPPORTS_MULTI_STATEMENT_WRITES,
SUPPORTS_REPORTING_WRITTEN_BYTES -> true; // FIXME: Fails because only allowed with transactional tables
case SUPPORTS_ADD_FIELD,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_ADD_FIELD,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
SUPPORTS_DROP_FIELD,
SUPPORTS_MERGE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import io.trino.spi.connector.CatalogSchemaTableName;
import io.trino.spi.connector.ColumnHandle;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.connector.ColumnPosition;
import io.trino.spi.connector.ConnectorAccessControl;
import io.trino.spi.connector.ConnectorAnalyzeMetadata;
import io.trino.spi.connector.ConnectorInsertTableHandle;
Expand Down Expand Up @@ -2442,7 +2443,7 @@ private static Term toIcebergTerm(Schema schema, PartitionField partitionField)
}

@Override
public void addColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnMetadata column)
public void addColumn(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnMetadata column, ColumnPosition position)
{
// Spark doesn't support adding a NOT NULL column to Iceberg tables
// Also, Spark throws an exception when reading the table if we add such columns and execute a rollback procedure
Expand All @@ -2456,9 +2457,14 @@ public void addColumn(ConnectorSession session, ConnectorTableHandle tableHandle
// added - instead of relying on addColumn in iceberg library to assign Ids
AtomicInteger nextFieldId = new AtomicInteger(icebergTable.schema().highestFieldId() + 2);
try {
icebergTable.updateSchema()
.addColumn(column.getName(), toIcebergTypeForNewColumn(column.getType(), nextFieldId), column.getComment())
.commit();
UpdateSchema updateSchema = icebergTable.updateSchema();
updateSchema.addColumn(column.getName(), toIcebergTypeForNewColumn(column.getType(), nextFieldId), column.getComment());
switch (position) {
case ColumnPosition.First _ -> updateSchema.moveFirst(column.getName());
case ColumnPosition.After after -> updateSchema.moveAfter(column.getName(), after.columnName());
case ColumnPosition.Last _ -> {}
}
updateSchema.commit();
}
catch (RuntimeException e) {
throw new TrinoException(ICEBERG_COMMIT_ERROR, "Failed to add column: " + firstNonNull(e.getMessage(), e), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ protected QueryRunner createQueryRunner()
protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
{
return switch (connectorBehavior) {
case SUPPORTS_ARRAY,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_ARRAY,
SUPPORTS_COMMENT_ON_COLUMN,
SUPPORTS_COMMENT_ON_TABLE,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
{
return switch (connectorBehavior) {
case SUPPORTS_TRUNCATE -> true;
case SUPPORTS_ADD_FIELD,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_ADD_FIELD,
SUPPORTS_AGGREGATION_PUSHDOWN,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
SUPPORTS_DELETE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public final void destroy()
protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior)
{
return switch (connectorBehavior) {
case SUPPORTS_ADD_FIELD,
case SUPPORTS_ADD_COLUMN_WITH_POSITION,
SUPPORTS_ADD_FIELD,
SUPPORTS_CREATE_MATERIALIZED_VIEW,
SUPPORTS_CREATE_VIEW,
SUPPORTS_DROP_FIELD,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_COLUMN;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_COLUMN_NOT_NULL_CONSTRAINT;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_COLUMN_WITH_COMMENT;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_COLUMN_WITH_POSITION;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_FIELD;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ADD_FIELD_IN_ARRAY;
import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ARRAY;
Expand Down Expand Up @@ -2412,6 +2413,40 @@ protected void verifyAddNotNullColumnToNonEmptyTableFailurePermissible(Throwable
throw new AssertionError("Unexpected failure when adding not null column", e);
}

@Test
public void testAddColumnWithPosition()
{
skipTestUnless(hasBehavior(SUPPORTS_ADD_COLUMN)); // covered by testAddColumn

if (!hasBehavior(SUPPORTS_ADD_COLUMN_WITH_POSITION)) {
try (TestTable table = new TestTable(getQueryRunner()::execute, "test_add_column_", "AS SELECT 2 second, 4 fourth")) {
assertQueryFails(
"ALTER TABLE " + table.getName() + " ADD COLUMN first integer FIRST",
"This connector does not support adding columns with FIRST clause");
assertQueryFails(
"ALTER TABLE " + table.getName() + " ADD COLUMN third integer AFTER second",
"This connector does not support adding columns with AFTER clause");
}
return;
}

try (TestTable table = new TestTable(getQueryRunner()::execute, "test_add_column_", "AS SELECT 2 second, 4 fourth")) {
assertTableColumnNames(table.getName(), "second", "fourth");
assertQuery("SELECT * FROM " + table.getName(), "VALUES (2, 4)");

assertUpdate("ALTER TABLE " + table.getName() + " ADD COLUMN first integer FIRST");
assertTableColumnNames(table.getName(), "first", "second", "fourth");
assertQuery("SELECT * FROM " + table.getName(), "VALUES (null, 2, 4)");

assertUpdate("ALTER TABLE " + table.getName() + " ADD COLUMN third integer AFTER second");
assertTableColumnNames(table.getName(), "first", "second", "third", "fourth");
assertQuery("SELECT * FROM " + table.getName(), "VALUES (null, 2, null, 4)");

assertUpdate("INSERT INTO " + table.getName() + " VALUES (10, 20, 30, 40)", 1);
assertQuery("SELECT * FROM " + table.getName(), "VALUES (null, 2, null, 4), (10, 20, 30, 40)");
}
}

@Test
public void testAddRowField()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public enum TestingConnectorBehavior

SUPPORTS_ADD_COLUMN,
SUPPORTS_ADD_COLUMN_WITH_COMMENT(SUPPORTS_ADD_COLUMN),
SUPPORTS_ADD_COLUMN_WITH_POSITION(SUPPORTS_ADD_COLUMN),
SUPPORTS_ADD_FIELD(fallback -> fallback.test(SUPPORTS_ADD_COLUMN) && fallback.test(SUPPORTS_ROW_TYPE)),
SUPPORTS_ADD_FIELD_IN_ARRAY(SUPPORTS_ADD_FIELD),
SUPPORTS_DROP_COLUMN(SUPPORTS_ADD_COLUMN),
Expand Down

0 comments on commit d949877

Please sign in to comment.