diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java index d7e06a1f926db..39982b6697848 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveIntegrationSmokeTest.java @@ -2051,10 +2051,12 @@ public void testMetadataDelete() assertEquals(e.getMessage(), "This connector only supports delete where one or more partitions are deleted entirely"); } + // Test successful metadata delete on partition columns assertUpdate("DELETE FROM test_metadata_delete WHERE LINE_STATUS='O'"); assertQuery("SELECT * from test_metadata_delete", "SELECT orderkey, linenumber, linestatus FROM lineitem WHERE linestatus<>'O' and linenumber<>3"); + // Test delete on non-partition column - should fail try { getQueryRunner().execute("DELETE FROM test_metadata_delete WHERE ORDER_KEY=1"); fail("expected exception"); @@ -2065,6 +2067,17 @@ public void testMetadataDelete() assertQuery("SELECT * from test_metadata_delete", "SELECT orderkey, linenumber, linestatus FROM lineitem WHERE linestatus<>'O' and linenumber<>3"); + // Test delete with partition column AND RAND() - should fail because RAND() requires row-level filtering + try { + getQueryRunner().execute("DELETE FROM test_metadata_delete WHERE LINE_STATUS='F' AND rand() <= 0.1"); + fail("expected exception"); + } + catch (RuntimeException e) { + assertEquals(e.getMessage(), "This connector only supports delete where one or more partitions are deleted entirely"); + } + + assertQuery("SELECT * from test_metadata_delete", "SELECT orderkey, linenumber, linestatus FROM lineitem WHERE linestatus<>'O' and linenumber<>3"); + assertUpdate("DROP TABLE test_metadata_delete"); assertFalse(getQueryRunner().tableExists(getSession(), "test_metadata_delete")); diff --git a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataDeleteOptimizer.java b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataDeleteOptimizer.java index c388ee2d4ca21..58ab23f719c4d 100644 --- a/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataDeleteOptimizer.java +++ b/presto-main-base/src/main/java/com/facebook/presto/sql/planner/optimizations/MetadataDeleteOptimizer.java @@ -15,6 +15,7 @@ import com.facebook.presto.Session; import com.facebook.presto.metadata.Metadata; +import com.facebook.presto.metadata.TableLayout; import com.facebook.presto.spi.VariableAllocator; import com.facebook.presto.spi.WarningCollector; import com.facebook.presto.spi.plan.DeleteNode; @@ -23,6 +24,7 @@ import com.facebook.presto.spi.plan.PlanNodeIdAllocator; import com.facebook.presto.spi.plan.TableFinishNode; import com.facebook.presto.spi.plan.TableScanNode; +import com.facebook.presto.spi.relation.RowExpression; import com.facebook.presto.sql.planner.TypeProvider; import com.facebook.presto.sql.planner.plan.ExchangeNode; import com.facebook.presto.sql.planner.plan.SimplePlanRewriter; @@ -31,6 +33,7 @@ import java.util.List; import java.util.Optional; +import static com.facebook.presto.expressions.LogicalRowExpressions.TRUE_CONSTANT; import static java.util.Objects.requireNonNull; /** @@ -101,6 +104,13 @@ public PlanNode visitTableFinish(TableFinishNode node, RewriteContext cont return context.defaultRewrite(node); } + // Check for remaining predicates that require row-level filtering. + // The remainingPredicate contains filters that couldn't be pushed down to the connector, + // such as non-deterministic functions (RAND(), UUID(), etc.) or complex expressions. + if (hasRemainingPredicates(tableScanNode)) { + return context.defaultRewrite(node); + } + planChanged = true; return new MetadataDeleteNode( node.getSourceLocation(), @@ -109,6 +119,22 @@ public PlanNode visitTableFinish(TableFinishNode node, RewriteContext cont Iterables.getOnlyElement(node.getOutputVariables())); } + private boolean hasRemainingPredicates(TableScanNode tableScanNode) + { + if (!tableScanNode.getTable().getLayout().isPresent()) { + return false; + } + + TableLayout tableLayout = metadata.getLayout(session, tableScanNode.getTable()); + + Optional remainingPredicate = tableLayout.getRemainingPredicate(); + if (remainingPredicate.isPresent() && !TRUE_CONSTANT.equals(remainingPredicate.get())) { + return true; + } + + return false; + } + private static Optional findNode(PlanNode source, Class clazz) { while (true) {