Skip to content

Commit 89deca5

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 60f11b8 commit 89deca5

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

src/test/regress/expected/union.out

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

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

src/test/regress/sql/union.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl ORDER BY 1;
112112

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

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy