Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ protected Scope visitInsert(Insert insert, Optional<Scope> scope)
Scope queryScope = analyze(insert.getQuery(), createScope(scope));

// verify the insert destination columns match the query
Optional<TableHandle> targetTableHandle = metadata.getTableHandle(session, targetTable);
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, targetTable);
Optional<TableHandle> targetTableHandle = redirection.getTableHandle();
targetTable = redirection.getRedirectedTableName().orElse(targetTable);
if (targetTableHandle.isEmpty()) {
throw semanticException(TABLE_NOT_FOUND, insert, "Table '%s' does not exist", targetTable);
}
Expand Down Expand Up @@ -659,12 +661,14 @@ private boolean hasBoundedCharacterType(Type type)
protected Scope visitDelete(Delete node, Optional<Scope> scope)
{
Table table = node.getTable();
QualifiedObjectName tableName = createQualifiedObjectName(session, table, table.getName());
if (metadata.getView(session, tableName).isPresent()) {
QualifiedObjectName originalName = createQualifiedObjectName(session, table, table.getName());
if (metadata.getView(session, originalName).isPresent()) {
throw semanticException(NOT_SUPPORTED, node, "Deleting from views is not supported");
}

TableHandle handle = metadata.getTableHandle(session, tableName)
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, originalName);
QualifiedObjectName tableName = redirection.getRedirectedTableName().orElse(originalName);
TableHandle handle = redirection.getTableHandle()
.orElseThrow(() -> semanticException(TABLE_NOT_FOUND, table, "Table '%s' does not exist", tableName));

accessControl.checkCanDeleteFromTable(session.toSecurityContext(), tableName);
Expand Down Expand Up @@ -2216,12 +2220,14 @@ else if (node.getType() == FULL) {
protected Scope visitUpdate(Update update, Optional<Scope> scope)
{
Table table = update.getTable();
QualifiedObjectName tableName = createQualifiedObjectName(session, table, table.getName());
if (metadata.getView(session, tableName).isPresent()) {
QualifiedObjectName originalName = createQualifiedObjectName(session, table, table.getName());
if (metadata.getView(session, originalName).isPresent()) {
throw semanticException(NOT_SUPPORTED, update, "Updating through views is not supported");
}

TableHandle handle = metadata.getTableHandle(session, tableName)
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, originalName);
QualifiedObjectName tableName = redirection.getRedirectedTableName().orElse(originalName);
TableHandle handle = redirection.getTableHandle()
.orElseThrow(() -> semanticException(TABLE_NOT_FOUND, table, "Table '%s' does not exist", tableName));

TableMetadata tableMetadata = metadata.getTableMetadata(session, handle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.google.common.collect.ImmutableList;
import io.airlift.slice.Slice;
import io.trino.spi.Page;
import io.trino.spi.block.Block;
import io.trino.spi.connector.AggregateFunction;
import io.trino.spi.connector.AggregationApplicationResult;
import io.trino.spi.connector.CatalogSchemaTableName;
Expand Down Expand Up @@ -470,6 +471,21 @@ public ColumnHandle getUpdateRowIdColumnHandle(ConnectorSession session, Connect
return new MockConnectorColumnHandle("update_row_id", BIGINT);
}

@Override
public ConnectorTableHandle beginDelete(ConnectorSession session, ConnectorTableHandle tableHandle)
{
return tableHandle;
}

@Override
public ColumnHandle getDeleteRowIdColumnHandle(ConnectorSession session, ConnectorTableHandle tableHandle)
{
return new MockConnectorColumnHandle("delete_row_id", BIGINT);
}

@Override
public void finishDelete(ConnectorSession session, ConnectorTableHandle tableHandle, Collection<Slice> fragments) {}

@Override
public boolean usesLegacyTableLayouts()
{
Expand Down Expand Up @@ -587,5 +603,8 @@ private static class MockPageSource
{
@Override
public void updateRows(Page page, List<Integer> columnValueAndRowIdChannels) {}

@Override
public void deleteRows(Block rowIds) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@
import com.google.common.collect.ImmutableSet;
import io.trino.Session;
import io.trino.connector.MockConnectorFactory;
import io.trino.connector.MockConnectorInsertTableHandle;
import io.trino.connector.MockConnectorPlugin;
import io.trino.connector.MockConnectorTableHandle;
import io.trino.spi.connector.CatalogSchemaTableName;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.connector.SchemaTableName;
import io.trino.spi.connector.TableColumnsMetadata;
import io.trino.sql.planner.Plan;
import io.trino.sql.planner.plan.TableFinishNode;
import io.trino.sql.planner.plan.TableScanNode;
import io.trino.sql.planner.plan.TableWriterNode;
import io.trino.testing.AbstractTestQueryFramework;
import io.trino.testing.DistributedQueryRunner;
import io.trino.testing.QueryRunner;
Expand Down Expand Up @@ -363,6 +366,66 @@ public void testShowColumns()
.hasMessageContaining("Table redirections form a loop");
}

@Test
public void testInsert()
{
assertUpdate(
getSession(),
format("INSERT INTO %s.%s VALUES (5, 6)", SCHEMA_ONE, VALID_REDIRECTION_SRC),
1,
// Verify the insert plan instead of through a successive SELECT, because insertion is a no-op for Mock connector
plan -> {
TableFinishNode finishNode = searchFrom(plan.getRoot())
.where(TableFinishNode.class::isInstance)
.findOnlyElement();
TableWriterNode.InsertTarget insertTarget = ((TableWriterNode.InsertTarget) finishNode.getTarget());
assertEquals(
((MockConnectorInsertTableHandle) insertTarget.getHandle().getConnectorHandle()).getTableName(),
schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
assertEquals(insertTarget.getSchemaTableName(), schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
});
}

@Test
public void testDelete()
{
assertUpdate(
getSession(),
format("DELETE FROM %s.%s WHERE %s = 5", SCHEMA_ONE, VALID_REDIRECTION_SRC, C2),
0,
// Verify the insert plan instead of through a successive SELECT, because deletion is a no-op for Mock connector
plan -> {
TableFinishNode finishNode = searchFrom(plan.getRoot())
.where(TableFinishNode.class::isInstance)
.findOnlyElement();
TableWriterNode.DeleteTarget deleteTarget = ((TableWriterNode.DeleteTarget) finishNode.getTarget());
assertEquals(
((MockConnectorTableHandle) deleteTarget.getHandle().get().getConnectorHandle()).getTableName(),
schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
assertEquals(deleteTarget.getSchemaTableName(), schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
});
}

@Test
public void testUpdate()
{
assertUpdate(
getSession(),
format("UPDATE %s.%s SET %s = 5 WHERE %s = 1", SCHEMA_ONE, VALID_REDIRECTION_SRC, C3, C2),
0,
// Verify the insert plan instead of through a successive SELECT, because update is a no-op for Mock connector
plan -> {
TableFinishNode finishNode = searchFrom(plan.getRoot())
.where(TableFinishNode.class::isInstance)
.findOnlyElement();
TableWriterNode.UpdateTarget updateTarget = ((TableWriterNode.UpdateTarget) finishNode.getTarget());
assertEquals(
((MockConnectorTableHandle) updateTarget.getHandle().get().getConnectorHandle()).getTableName(),
schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
assertEquals(updateTarget.getSchemaTableName(), schemaTableName(SCHEMA_TWO, VALID_REDIRECTION_TARGET));
});
}

// TODO: Add tests for redirection in CommentsSystemTable and CREATE TABLE LIKE

private static String row(String... values)
Expand Down