Repository: prestodb/presto
Issue: Incorrect results when cross joining against aggregation over partitioned table

This query:

``` sql
SELECT * FROM (VALUES 1, 2, 3) t CROSS JOIN (SELECT count(*) FROM table WHERE pk = 'non-existent') u
```

(`pk` is a partition key for `table`)

produces an incorrect plan:

```
 - Output[_col0, _col1] => [field:bigint, count:bigint]
         _col0 := field
         _col1 := count
     - InnerJoin[] => [field:bigint, count:bigint]
         - Filter[false] => [field:bigint]
             - Values => [field:bigint]
                     (1)
                     (2)
                     (3)
         - Aggregate(FINAL) => [count:bigint]
                 count := "count"("count_235")
             - Exchange[GATHER] => count_235:bigint
                 - Aggregate(PARTIAL) => [count_235:bigint]
                         count_235 := "count"(*)
                     - TableScan[...] => []
                             :: NONE
```

It seems to be pushing the "false" predicate (due to no matching partitions) up through the aggregation and pushing it down on the left side.


Changed files:
presto-main/src/test/java/com/facebook/presto/sql/planner/TestEffectivePredicateExtractor.java
presto-main/src/main/java/com/facebook/presto/sql/planner/EffectivePredicateExtractor.java

diff --git a/presto-main/src/main/java/com/facebook/presto/sql/planner/EffectivePredicateExtractor.java b/presto-main/src/main/java/com/facebook/presto/sql/planner/EffectivePredicateExtractor.java
index ac5ebf2d10..9f6ba10ef6 100644
--- a/presto-main/src/main/java/com/facebook/presto/sql/planner/EffectivePredicateExtractor.java
+++ b/presto-main/src/main/java/com/facebook/presto/sql/planner/EffectivePredicateExtractor.java
@@ -100,6 +100,15 @@ public class EffectivePredicateExtractor
     @Override
     public Expression visitAggregation(AggregationNode node, Void context)
     {
+        // GROUP BY () always produces a group, regardless of whether there's any
+        // input (unlike the case where there are group by keys, which produce
+        // no output if there's no input).
+        // Therefore, we can't say anything about the effective predicate of the
+        // output of such an aggregation.
+        if (node.getGroupBy().isEmpty()) {
+            return TRUE_LITERAL;
+        }
+
         Expression underlyingPredicate = node.getSource().accept(this, context);
 
         return pullExpressionThroughSymbols(underlyingPredicate, node.getGroupBy());
diff --git a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestEffectivePredicateExtractor.java b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestEffectivePredicateExtractor.java
index b0eb0b7cf8..5b2b25836c 100644
--- a/presto-main/src/test/java/com/facebook/presto/sql/planner/TestEffectivePredicateExtractor.java
+++ b/presto-main/src/test/java/com/facebook/presto/sql/planner/TestEffectivePredicateExtractor.java
@@ -72,6 +72,7 @@ import static com.facebook.presto.sql.ExpressionUtils.and;
 import static com.facebook.presto.sql.ExpressionUtils.combineConjuncts;
 import static com.facebook.presto.sql.ExpressionUtils.or;
 import static com.facebook.presto.sql.tree.BooleanLiteral.FALSE_LITERAL;
+import static com.facebook.presto.sql.tree.BooleanLiteral.TRUE_LITERAL;
 import static org.testng.Assert.assertEquals;
 
 @Test(singleThreaded = true)
@@ -167,6 +168,28 @@ public class TestEffectivePredicateExtractor
                         equals(BE, CE)));
     }
 
+    @Test
+    public void testGroupByEmpty()
+            throws Exception
+    {
+        PlanNode node = new AggregationNode(
+                newId(),
+                filter(baseTableScan, FALSE_LITERAL),
+                ImmutableList.of(),
+                ImmutableMap.of(),
+                ImmutableMap.of(),
+                ImmutableMap.of(),
+                ImmutableList.of(),
+                AggregationNode.Step.FINAL,
+                Optional.empty(),
+                1.0,
+                Optional.empty());
+
+        Expression effectivePredicate = EffectivePredicateExtractor.extract(node, TYPES);
+
+        assertEquals(effectivePredicate, TRUE_LITERAL);
+    }
+
     @Test
     public void testFilter()
             throws Exception