Skip to content

Commit

Permalink
Improve exception handling for CREATE TABLE task
Browse files Browse the repository at this point in the history
Provide meaningful exception message for `CREATE TABLE` task
when dealing with namesake table of unsupported type in
shared metastore.

This change affects the connectors: hive, iceberg, delta lake
which may deal with a shared metastore (HMS/AWS Glue).
  • Loading branch information
findinpath committed Mar 23, 2022
1 parent adb45f1 commit e50cbc3
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import static io.trino.spi.StandardErrorCode.TABLE_ALREADY_EXISTS;
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.TYPE_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.UNSUPPORTED_TABLE_TYPE;
import static io.trino.spi.connector.ConnectorCapabilities.NOT_NULL_COLUMN_CONSTRAINT;
import static io.trino.sql.ParameterUtils.parameterExtractor;
import static io.trino.sql.analyzer.SemanticExceptions.semanticException;
Expand Down Expand Up @@ -125,7 +126,16 @@ ListenableFuture<Void> internalExecute(CreateTable statement, Session session, L

Map<NodeRef<Parameter>, Expression> parameterLookup = parameterExtractor(statement, parameters);
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getName());
Optional<TableHandle> tableHandle = plannerContext.getMetadata().getTableHandle(session, tableName);
Optional<TableHandle> tableHandle;
try {
tableHandle = plannerContext.getMetadata().getTableHandle(session, tableName);
}
catch (TrinoException e) {
if (e.getErrorCode().equals(UNSUPPORTED_TABLE_TYPE.toErrorCode())) {
throw semanticException(TABLE_ALREADY_EXISTS, statement, "Table '%s' of unsupported type already exists", tableName);
}
throw e;
}
if (tableHandle.isPresent()) {
if (!statement.isNotExists()) {
throw semanticException(TABLE_ALREADY_EXISTS, statement, "Table '%s' already exists", tableName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public enum StandardErrorCode
MISSING_ROW_PATTERN(106, USER_ERROR),
INVALID_WINDOW_MEASURE(107, USER_ERROR),
STACK_OVERFLOW(108, USER_ERROR),
UNSUPPORTED_TABLE_TYPE(109, USER_ERROR),

GENERIC_INTERNAL_ERROR(65536, INTERNAL_ERROR),
TOO_MANY_REQUESTS_FAILED(65537, INTERNAL_ERROR),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import io.trino.spi.TrinoException;

import static io.trino.plugin.deltalake.DeltaLakeErrorCode.DELTA_LAKE_INVALID_TABLE;
import static io.trino.spi.StandardErrorCode.UNSUPPORTED_TABLE_TYPE;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

Expand All @@ -25,7 +25,7 @@ public class NotADeltaLakeTableException
public NotADeltaLakeTableException(String databaseName, String tableName)
{
super(
DELTA_LAKE_INVALID_TABLE,
UNSUPPORTED_TABLE_TYPE,
format("%s.%s is not a Delta Lake table", requireNonNull(databaseName, "databaseName is null"), requireNonNull(tableName, "tableName is null")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@
import static io.trino.spi.StandardErrorCode.INVALID_TABLE_PROPERTY;
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
import static io.trino.spi.StandardErrorCode.UNSUPPORTED_TABLE_TYPE;
import static io.trino.spi.connector.Constraint.alwaysTrue;
import static io.trino.spi.connector.RetryMode.NO_RETRIES;
import static io.trino.spi.predicate.TupleDomain.withColumnDomains;
Expand Down Expand Up @@ -438,10 +439,10 @@ public HiveTableHandle getTableHandle(ConnectorSession session, SchemaTableName
}

if (isDeltaLakeTable(table)) {
throw new TrinoException(HIVE_UNSUPPORTED_FORMAT, format("Cannot query Delta Lake table '%s'", tableName));
throw new TrinoException(UNSUPPORTED_TABLE_TYPE, format("Cannot query Delta Lake table '%s'", tableName));
}
if (isIcebergTable(table)) {
throw new TrinoException(HIVE_UNSUPPORTED_FORMAT, format("Cannot query Iceberg table '%s'", tableName));
throw new TrinoException(UNSUPPORTED_TABLE_TYPE, format("Cannot query Iceberg table '%s'", tableName));
}

// we must not allow system tables due to how permissions are checked in SystemTableAwareAccessControl
Expand Down Expand Up @@ -560,7 +561,7 @@ private ConnectorTableMetadata doGetTableMetadata(ConnectorSession session, Sche
.orElseThrow(() -> new TableNotFoundException(tableName));

if (isIcebergTable(table) || isDeltaLakeTable(table)) {
throw new TrinoException(HIVE_UNSUPPORTED_FORMAT, format("Not a Hive table '%s'", tableName));
throw new TrinoException(UNSUPPORTED_TABLE_TYPE, format("Not a Hive table '%s'", tableName));
}

if (!translateHiveViews && isHiveOrPrestoView(table)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
public enum IcebergErrorCode
implements ErrorCodeSupplier
{
ICEBERG_UNKNOWN_TABLE_TYPE(0, EXTERNAL),
// code ICEBERG_UNKNOWN_TABLE_TYPE(0, EXTERNAL) is deprecated
ICEBERG_INVALID_METADATA(1, EXTERNAL),
ICEBERG_TOO_MANY_OPEN_PARTITIONS(2, USER_ERROR),
ICEBERG_INVALID_PARTITION_VALUE(3, EXTERNAL),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import io.trino.spi.TrinoException;
import io.trino.spi.connector.SchemaTableName;

import static io.trino.plugin.iceberg.IcebergErrorCode.ICEBERG_UNKNOWN_TABLE_TYPE;
import static io.trino.spi.StandardErrorCode.UNSUPPORTED_TABLE_TYPE;
import static java.util.Objects.requireNonNull;

public class UnknownTableTypeException
Expand All @@ -26,7 +26,7 @@ public class UnknownTableTypeException

public UnknownTableTypeException(SchemaTableName tableName)
{
super(ICEBERG_UNKNOWN_TABLE_TYPE, "Not an Iceberg table: " + tableName);
super(UNSUPPORTED_TABLE_TYPE, "Not an Iceberg table: " + tableName);
this.tableName = requireNonNull(tableName, "tableName is null");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,28 @@ public void testHiveSelectFromIcebergTable()

onTrino().executeQuery("DROP TABLE iceberg.default." + tableName);
}

@Test(groups = {ICEBERG, STORAGE_FORMATS, HMS_ONLY})
public void testIcebergCannotCreateTableNamesakeToHiveTable()
{
String tableName = "test_iceberg_create_namesake_hive_table_" + randomTableSuffix();
onTrino().executeQuery("CREATE TABLE hive.default." + tableName + "(a bigint)");

assertQueryFailure(() -> onTrino().executeQuery("CREATE TABLE iceberg.default." + tableName + "(a bigint)"))
.hasMessageMatching("Query failed \\(#\\w+\\):\\Q line 1:1: Table 'iceberg.default." + tableName + "' of unsupported type already exists");

onTrino().executeQuery("DROP TABLE hive.default." + tableName);
}

@Test(groups = {ICEBERG, STORAGE_FORMATS, HMS_ONLY})
public void testHiveCannotCreateTableNamesakeToIcebergTable()
{
String tableName = "test_hive_create_namesake_iceberg_table_" + randomTableSuffix();
onTrino().executeQuery("CREATE TABLE iceberg.default." + tableName + "(a bigint)");

assertQueryFailure(() -> onTrino().executeQuery("CREATE TABLE hive.default." + tableName + "(a bigint)"))
.hasMessageMatching("Query failed \\(#\\w+\\):\\Q line 1:1: Table 'hive.default." + tableName + "' of unsupported type already exists");

onTrino().executeQuery("DROP TABLE iceberg.default." + tableName);
}
}

0 comments on commit e50cbc3

Please sign in to comment.