Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c0a493e

Browse files
committed
Fix planner error (or assert trap) with nested set operations.
As reported by Sean Johnston in bug #14614, since 9.6 the planner can fail due to trying to look up the referent of a Var with varno 0. This happens because we generate such Vars in generate_append_tlist, for lack of any better way to describe the output of a SetOp node. In typical situations nothing really cares about that, but given nested set-operation queries we will call estimate_num_groups on the output of the subquery, and that wants to know what a Var actually refers to. That logic used to look at subquery->targetList, but in commit 3fc6e2d I'd switched it to look at subroot->processed_tlist, ie the actual output of the subquery plan not the parser's idea of the result. It seemed like a good idea at the time :-(. As a band-aid fix, change it back. Really we ought to have an honest way of naming the outputs of SetOp steps, which suggests that it'd be a good idea for the parser to emit an RTE corresponding to each one. But that's a task for another day, and it certainly wouldn't yield a back-patchable fix. Report: https://postgr.es/m/20170407115808.25934.51866@wrigleys.postgresql.org
1 parent dd93afc commit c0a493e

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

src/backend/optimizer/prep/prepunion.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,16 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
338338
* Estimate number of groups if caller wants it. If the subquery used
339339
* grouping or aggregation, its output is probably mostly unique
340340
* anyway; otherwise do statistical estimation.
341+
*
342+
* XXX you don't really want to know about this: we do the estimation
343+
* using the subquery's original targetlist expressions, not the
344+
* subroot->processed_tlist which might seem more appropriate. The
345+
* reason is that if the subquery is itself a setop, it may return a
346+
* processed_tlist containing "varno 0" Vars generated by
347+
* generate_append_tlist, and those would confuse estimate_num_groups
348+
* mightily. We ought to get rid of the "varno 0" hack, but that
349+
* requires a redesign of the parsetree representation of setops, so
350+
* that there can be an RTE corresponding to each setop's output.
341351
*/
342352
if (pNumGroups)
343353
{
@@ -347,7 +357,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
347357
*pNumGroups = subpath->rows;
348358
else
349359
*pNumGroups = estimate_num_groups(subroot,
350-
get_tlist_exprs(subroot->processed_tlist, false),
360+
get_tlist_exprs(subquery->targetList, false),
351361
subpath->rows,
352362
NULL);
353363
}

src/test/regress/expected/union.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,31 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl;
319319

320320
SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE;
321321
ERROR: FOR NO KEY UPDATE is not allowed with UNION/INTERSECT/EXCEPT
322+
-- nested cases
323+
(SELECT 1,2,3 UNION SELECT 4,5,6) INTERSECT SELECT 4,5,6;
324+
?column? | ?column? | ?column?
325+
----------+----------+----------
326+
4 | 5 | 6
327+
(1 row)
328+
329+
(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) INTERSECT SELECT 4,5,6;
330+
?column? | ?column? | ?column?
331+
----------+----------+----------
332+
4 | 5 | 6
333+
(1 row)
334+
335+
(SELECT 1,2,3 UNION SELECT 4,5,6) EXCEPT SELECT 4,5,6;
336+
?column? | ?column? | ?column?
337+
----------+----------+----------
338+
1 | 2 | 3
339+
(1 row)
340+
341+
(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) EXCEPT SELECT 4,5,6;
342+
?column? | ?column? | ?column?
343+
----------+----------+----------
344+
1 | 2 | 3
345+
(1 row)
346+
322347
--
323348
-- Mixed types
324349
--

src/test/regress/sql/union.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl;
111111

112112
SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE;
113113

114+
-- nested cases
115+
(SELECT 1,2,3 UNION SELECT 4,5,6) INTERSECT SELECT 4,5,6;
116+
(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) INTERSECT SELECT 4,5,6;
117+
(SELECT 1,2,3 UNION SELECT 4,5,6) EXCEPT SELECT 4,5,6;
118+
(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) EXCEPT SELECT 4,5,6;
119+
114120
--
115121
-- Mixed types
116122
--

0 commit comments

Comments
 (0)