From dd5ecb9deba077d37fb99de2c31dbf53db1e858a Mon Sep 17 00:00:00 2001 From: Dimitris Tsirogiannis Date: Mon, 20 Apr 2015 17:06:26 -0700 Subject: [PATCH] IMPALA-1960: Illegal reference to non-materialized tuple when query has an empty select-project-join block This commit fixes an issue where an aggregation expr may reference a non-materialized slot if the query contains an empty select-project-join block. This fix ensures that all the exprs in an aggregation reference materialized slots/tuples. Change-Id: Ic2cc9818061b3f06ab1d1cebf4e604352c2df6d1 Reviewed-on: http://gerrit.cloudera.org:8080/348 Reviewed-by: Dimitris Tsirogiannis Tested-by: Internal Jenkins --- .../impala/planner/SingleNodePlanner.java | 19 +++++---- .../queries/PlannerTest/empty.test | 41 +++++++++++++++++++ .../queries/QueryTest/empty.test | 12 ++++++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/fe/src/main/java/com/cloudera/impala/planner/SingleNodePlanner.java b/fe/src/main/java/com/cloudera/impala/planner/SingleNodePlanner.java index 89af0d87d..b56ad3441 100644 --- a/fe/src/main/java/com/cloudera/impala/planner/SingleNodePlanner.java +++ b/fe/src/main/java/com/cloudera/impala/planner/SingleNodePlanner.java @@ -487,12 +487,6 @@ public class SingleNodePlanner { return createConstantSelectPlan(selectStmt, analyzer); } - // collect output tuples of subtrees - ArrayList rowTuples = Lists.newArrayList(); - for (TableRef tblRef: selectStmt.getTableRefs()) { - rowTuples.addAll(tblRef.getMaterializedTupleIds()); - } - // Slot materialization: // We need to mark all slots as materialized that are needed during the execution // of selectStmt, and we need to do that prior to creating plans for the TableRefs @@ -507,11 +501,20 @@ public class SingleNodePlanner { // process repeats itself. selectStmt.materializeRequiredSlots(analyzer); - // return a plan that feeds the aggregation of selectStmt with an empty set, - // if the selectStmt's select-project-join portion returns an empty result set + ArrayList rowTuples = Lists.newArrayList(); + // collect output tuples of subtrees + for (TableRef tblRef: selectStmt.getTableRefs()) { + rowTuples.addAll(tblRef.getMaterializedTupleIds()); + } + + // If the selectStmt's select-project-join portion returns an empty result set + // create a plan that feeds the aggregation of selectStmt with an empty set. + // Make sure the slots of the aggregation exprs and the tuples that they reference + // are materialized (see IMPALA-1960). if (analyzer.hasEmptySpjResultSet()) { PlanNode emptySetNode = new EmptySetNode(ctx_.getNextNodeId(), rowTuples); emptySetNode.init(analyzer); + emptySetNode.setOutputSmap(selectStmt.getBaseTblSmap()); return createAggregationPlan(selectStmt, analyzer, emptySetNode); } diff --git a/testdata/workloads/functional-planner/queries/PlannerTest/empty.test b/testdata/workloads/functional-planner/queries/PlannerTest/empty.test index 37b3000a1..56259e027 100644 --- a/testdata/workloads/functional-planner/queries/PlannerTest/empty.test +++ b/testdata/workloads/functional-planner/queries/PlannerTest/empty.test @@ -278,3 +278,44 @@ WRITE TO HDFS [default.test_1860, OVERWRITE=false] | 00:EMPTYSET ==== +# IMPALA-1960: Exprs in the aggregation that reference slots from an inline view when +# the select stmt has an empty select-project-join portion. +select sum(T.id), count(T.int_col) +from + (select id, int_col, bigint_col from functional.alltypestiny) T +where false +---- PLAN +01:AGGREGATE [FINALIZE] +| output: sum(id), count(int_col) +| +00:EMPTYSET +==== +# IMPALA-1960: Exprs in the aggregation that reference slots from an inline view when +# the select stmt has an empty select-project-join portion. +select sum(T1.id + T2.int_col) +from + (select id, bigint_col from functional.alltypestiny) T1 inner join + (select id, int_col from functional.alltypestiny) T2 on (T1.id = T2.id) +where T1.bigint_col < 10 and 1 > 1 +---- PLAN +01:AGGREGATE [FINALIZE] +| output: sum(id + int_col) +| +00:EMPTYSET +==== +# IMPALA-1960: Exprs in the aggregation that reference slots from an inline view when +# the select stmt has an empty select-project-join portion. +select count(distinct T1.int_col) +from + (select id, int_col from functional.alltypestiny) T1 inner join + functional.alltypessmall T2 on T1.id = T2.id +where T2.bigint_col < 10 and false +---- PLAN +02:AGGREGATE [FINALIZE] +| output: count(T1.int_col) +| +01:AGGREGATE +| group by: int_col +| +00:EMPTYSET +==== diff --git a/testdata/workloads/functional-query/queries/QueryTest/empty.test b/testdata/workloads/functional-query/queries/QueryTest/empty.test index 014dd67d7..6445bafc2 100644 --- a/testdata/workloads/functional-query/queries/QueryTest/empty.test +++ b/testdata/workloads/functional-query/queries/QueryTest/empty.test @@ -117,3 +117,15 @@ WHERE (-339.22) IN (-922.68, -254.84) ---- TYPES INT ==== +---- QUERY +# IMPALA-1960: Exprs in the aggregation that reference slots from an inline view when +# the select stmt has an empty select-project-join portion. +select sum(T.id), count(T.int_col) +from + (select id, int_col, bigint_col from functional.alltypestiny) T +where false +---- RESULTS +NULL,0 +---- TYPES +BIGINT, BIGINT +====