diff --git a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java index ad9f4c72d3f6..5acf3e44e694 100644 --- a/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java +++ b/plugin/trino-delta-lake/src/main/java/io/trino/plugin/deltalake/DeltaLakeMetadata.java @@ -317,6 +317,7 @@ public class DeltaLakeMetadata public static final String MERGE_OPERATION = "MERGE"; public static final String UPDATE_OPERATION = "UPDATE"; // used by old Trino versions and Spark public static final String DELETE_OPERATION = "DELETE"; // used Trino for whole table/partition deletes as well as Spark + public static final String TRUNCATE_OPERATION = "TRUNCATE"; public static final String OPTIMIZE_OPERATION = "OPTIMIZE"; public static final String SET_TBLPROPERTIES_OPERATION = "SET TBLPROPERTIES"; public static final String CHANGE_COLUMN_OPERATION = "CHANGE COLUMN"; @@ -3259,6 +3260,12 @@ public WriterScalingOptions getInsertWriterScalingOptions(ConnectorSession sessi return WriterScalingOptions.ENABLED; } + @Override + public void truncateTable(ConnectorSession session, ConnectorTableHandle tableHandle) + { + executeDelete(session, checkValidTableHandle(tableHandle), TRUNCATE_OPERATION); + } + @Override public Optional applyDelete(ConnectorSession session, ConnectorTableHandle handle) { @@ -3273,6 +3280,11 @@ public Optional applyDelete(ConnectorSession session, Conn @Override public OptionalLong executeDelete(ConnectorSession session, ConnectorTableHandle handle) + { + return executeDelete(session, handle, DELETE_OPERATION); + } + + private OptionalLong executeDelete(ConnectorSession session, ConnectorTableHandle handle, String operation) { DeltaLakeTableHandle tableHandle = (DeltaLakeTableHandle) handle; if (isAppendOnly(tableHandle.getMetadataEntry())) { @@ -3294,7 +3306,7 @@ public OptionalLong executeDelete(ConnectorSession session, ConnectorTableHandle throw new TransactionConflictException(format("Conflicting concurrent writes found. Expected transaction log version: %s, actual version: %s", tableHandle.getReadVersion(), currentVersion)); } long commitVersion = currentVersion + 1; - transactionLogWriter.appendCommitInfoEntry(getCommitInfoEntry(session, commitVersion, writeTimestamp, DELETE_OPERATION, tableHandle.getReadVersion())); + transactionLogWriter.appendCommitInfoEntry(getCommitInfoEntry(session, commitVersion, writeTimestamp, operation, tableHandle.getReadVersion())); long deletedRecords = 0L; boolean allDeletedFilesStatsPresent = true; diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/BaseDeltaLakeConnectorSmokeTest.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/BaseDeltaLakeConnectorSmokeTest.java index 4ac8d64507b4..b97e39c751e8 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/BaseDeltaLakeConnectorSmokeTest.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/BaseDeltaLakeConnectorSmokeTest.java @@ -232,8 +232,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) { return switch (connectorBehavior) { case SUPPORTS_CREATE_MATERIALIZED_VIEW, - SUPPORTS_RENAME_SCHEMA, - SUPPORTS_TRUNCATE -> false; + SUPPORTS_RENAME_SCHEMA -> false; default -> super.hasBehavior(connectorBehavior); }; } diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeBasic.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeBasic.java index b00985d69269..03e5d99bbfa8 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeBasic.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeBasic.java @@ -651,7 +651,7 @@ private void testCorruptedTableLocation(String tableName, Path tableLocation, bo assertQueryFails("UPDATE " + tableName + " SET foo = 'bar'", "Metadata not found in transaction log for tpch." + tableName); assertQueryFails("DELETE FROM " + tableName, "Metadata not found in transaction log for tpch." + tableName); assertQueryFails("MERGE INTO " + tableName + " USING (SELECT 1 a) input ON true WHEN MATCHED THEN DELETE", "Metadata not found in transaction log for tpch." + tableName); - assertQueryFails("TRUNCATE TABLE " + tableName, "This connector does not support truncating tables"); + assertQueryFails("TRUNCATE TABLE " + tableName, "Metadata not found in transaction log for tpch." + tableName); assertQueryFails("COMMENT ON TABLE " + tableName + " IS NULL", "Metadata not found in transaction log for tpch." + tableName); assertQueryFails("COMMENT ON COLUMN " + tableName + ".foo IS NULL", "Metadata not found in transaction log for tpch." + tableName); assertQueryFails("CALL system.vacuum(CURRENT_SCHEMA, '" + tableName + "', '7d')", "Metadata not found in transaction log for tpch." + tableName); diff --git a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeConnectorTest.java b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeConnectorTest.java index 4b4565b8bc0c..0f747022e724 100644 --- a/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeConnectorTest.java +++ b/plugin/trino-delta-lake/src/test/java/io/trino/plugin/deltalake/TestDeltaLakeConnectorTest.java @@ -155,8 +155,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) SUPPORTS_RENAME_FIELD, SUPPORTS_RENAME_SCHEMA, SUPPORTS_SET_COLUMN_TYPE, - SUPPORTS_TOPN_PUSHDOWN, - SUPPORTS_TRUNCATE -> false; + SUPPORTS_TOPN_PUSHDOWN -> false; default -> super.hasBehavior(connectorBehavior); }; } diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/deltalake/TestDeltaLakeDeleteCompatibility.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/deltalake/TestDeltaLakeDeleteCompatibility.java index 7aeb1b017c0d..2a49fd55e3f2 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/deltalake/TestDeltaLakeDeleteCompatibility.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/deltalake/TestDeltaLakeDeleteCompatibility.java @@ -90,12 +90,38 @@ public void testDeleteOnAppendOnlyTableFails() // Whole table deletes should be disallowed as well assertQueryFailure(() -> onTrino().executeQuery("DELETE FROM default." + tableName)) .hasMessageContaining("Cannot modify rows from a table with 'delta.appendOnly' set to true"); + assertQueryFailure(() -> onTrino().executeQuery("TRUNCATE TABLE delta.default." + tableName)) + .hasMessageContaining("Cannot modify rows from a table with 'delta.appendOnly' set to true"); assertThat(onDelta().executeQuery("SELECT * FROM default." + tableName)) .containsOnly(row(1, 11), row(2, 12)); onTrino().executeQuery("DROP TABLE " + tableName); } + // OSS Delta doesn't support TRUNCATE TABLE statement + @Test(groups = {DELTA_LAKE_DATABRICKS, PROFILE_SPECIFIC_TESTS}) + @Flaky(issue = DATABRICKS_COMMUNICATION_FAILURE_ISSUE, match = DATABRICKS_COMMUNICATION_FAILURE_MATCH) + public void testTruncateTable() + { + String tableName = "test_truncate_table_" + randomNameSuffix(); + onTrino().executeQuery("" + + "CREATE TABLE delta.default." + tableName + + "(a INT)" + + "WITH (location = 's3://" + bucketName + "/databricks-compatibility-test-" + tableName + "')"); + try { + onTrino().executeQuery("INSERT INTO delta.default." + tableName + " VALUES 1, 2, 3"); + onTrino().executeQuery("TRUNCATE TABLE delta.default." + tableName); + assertThat(onDelta().executeQuery("SELECT * FROM default." + tableName)).hasNoRows(); + + onDelta().executeQuery("INSERT INTO default." + tableName + " VALUES 4, 5, 6"); + onDelta().executeQuery("TRUNCATE TABLE default." + tableName); + assertThat(onTrino().executeQuery("SELECT * FROM delta.default." + tableName)).hasNoRows(); + } + finally { + onTrino().executeQuery("DROP TABLE delta.default." + tableName); + } + } + // Databricks 12.1 and OSS Delta 2.4.0 added support for deletion vectors @Test(groups = {DELTA_LAKE_DATABRICKS, DELTA_LAKE_OSS, DELTA_LAKE_EXCLUDE_73, DELTA_LAKE_EXCLUDE_91, DELTA_LAKE_EXCLUDE_104, DELTA_LAKE_EXCLUDE_113, PROFILE_SPECIFIC_TESTS}) @Flaky(issue = DATABRICKS_COMMUNICATION_FAILURE_ISSUE, match = DATABRICKS_COMMUNICATION_FAILURE_MATCH)