mirror of
https://github.com/postgres/postgres.git
synced 2025-05-06 19:59:18 +03:00
Fix "cannot handle unplanned sub-select" error that can occur when a
sub-select contains a join alias reference that expands into an expression containing another sub-select. Per yesterday's report from Merlin Moncure and subsequent off-list investigation. Back-patch to 7.4. Older versions didn't attempt to flatten sub-selects in ways that would trigger this problem.
This commit is contained in:
parent
9e3a7f50e4
commit
473c29e6ae
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.68 2006/07/14 14:52:21 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.68.2.1 2010/07/08 00:14:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -50,6 +50,8 @@ typedef struct
|
|||||||
{
|
{
|
||||||
PlannerInfo *root;
|
PlannerInfo *root;
|
||||||
int sublevels_up;
|
int sublevels_up;
|
||||||
|
bool possible_sublink; /* could aliases include a SubLink? */
|
||||||
|
bool inserted_sublink; /* have we inserted a SubLink? */
|
||||||
} flatten_join_alias_vars_context;
|
} flatten_join_alias_vars_context;
|
||||||
|
|
||||||
static bool pull_varnos_walker(Node *node,
|
static bool pull_varnos_walker(Node *node,
|
||||||
@ -475,6 +477,14 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
|||||||
* is necessary since we will not scan the JOIN as a base relation, which
|
* is necessary since we will not scan the JOIN as a base relation, which
|
||||||
* is the only way that the executor can directly handle whole-row Vars.
|
* is the only way that the executor can directly handle whole-row Vars.
|
||||||
*
|
*
|
||||||
|
* If a JOIN contains sub-selects that have been flattened, its join alias
|
||||||
|
* entries might now be arbitrary expressions, not just Vars. This affects
|
||||||
|
* this function in one important way: we might find ourselves inserting
|
||||||
|
* SubLink expressions into subqueries, and we must make sure that their
|
||||||
|
* Query.hasSubLinks fields get set to TRUE if so. If there are any
|
||||||
|
* SubLinks in the join alias lists, the outer Query should already have
|
||||||
|
* hasSubLinks = TRUE, so this is only relevant to un-flattened subqueries.
|
||||||
|
*
|
||||||
* NOTE: this is used on not-yet-planned expressions. We do not expect it
|
* NOTE: this is used on not-yet-planned expressions. We do not expect it
|
||||||
* to be applied directly to a Query node.
|
* to be applied directly to a Query node.
|
||||||
*/
|
*/
|
||||||
@ -485,6 +495,10 @@ flatten_join_alias_vars(PlannerInfo *root, Node *node)
|
|||||||
|
|
||||||
context.root = root;
|
context.root = root;
|
||||||
context.sublevels_up = 0;
|
context.sublevels_up = 0;
|
||||||
|
/* flag whether join aliases could possibly contain SubLinks */
|
||||||
|
context.possible_sublink = root->parse->hasSubLinks;
|
||||||
|
/* if hasSubLinks is already true, no need to work hard */
|
||||||
|
context.inserted_sublink = root->parse->hasSubLinks;
|
||||||
|
|
||||||
return flatten_join_alias_vars_mutator(node, &context);
|
return flatten_join_alias_vars_mutator(node, &context);
|
||||||
}
|
}
|
||||||
@ -534,6 +548,7 @@ flatten_join_alias_vars_mutator(Node *node,
|
|||||||
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
|
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
|
||||||
}
|
}
|
||||||
/* Recurse in case join input is itself a join */
|
/* Recurse in case join input is itself a join */
|
||||||
|
/* (also takes care of setting inserted_sublink if needed) */
|
||||||
newvar = flatten_join_alias_vars_mutator(newvar, context);
|
newvar = flatten_join_alias_vars_mutator(newvar, context);
|
||||||
fields = lappend(fields, newvar);
|
fields = lappend(fields, newvar);
|
||||||
}
|
}
|
||||||
@ -558,8 +573,15 @@ flatten_join_alias_vars_mutator(Node *node,
|
|||||||
newvar = copyObject(newvar);
|
newvar = copyObject(newvar);
|
||||||
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
|
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recurse in case join input is itself a join */
|
/* Recurse in case join input is itself a join */
|
||||||
return flatten_join_alias_vars_mutator(newvar, context);
|
newvar = flatten_join_alias_vars_mutator(newvar, context);
|
||||||
|
|
||||||
|
/* Detect if we are adding a sublink to query */
|
||||||
|
if (context->possible_sublink && !context->inserted_sublink)
|
||||||
|
context->inserted_sublink = checkExprHasSubLink(newvar);
|
||||||
|
|
||||||
|
return newvar;
|
||||||
}
|
}
|
||||||
if (IsA(node, InClauseInfo))
|
if (IsA(node, InClauseInfo))
|
||||||
{
|
{
|
||||||
@ -584,12 +606,17 @@ flatten_join_alias_vars_mutator(Node *node,
|
|||||||
{
|
{
|
||||||
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
||||||
Query *newnode;
|
Query *newnode;
|
||||||
|
bool save_inserted_sublink;
|
||||||
|
|
||||||
context->sublevels_up++;
|
context->sublevels_up++;
|
||||||
|
save_inserted_sublink = context->inserted_sublink;
|
||||||
|
context->inserted_sublink = ((Query *) node)->hasSubLinks;
|
||||||
newnode = query_tree_mutator((Query *) node,
|
newnode = query_tree_mutator((Query *) node,
|
||||||
flatten_join_alias_vars_mutator,
|
flatten_join_alias_vars_mutator,
|
||||||
(void *) context,
|
(void *) context,
|
||||||
QTW_IGNORE_JOINALIASES);
|
QTW_IGNORE_JOINALIASES);
|
||||||
|
newnode->hasSubLinks |= context->inserted_sublink;
|
||||||
|
context->inserted_sublink = save_inserted_sublink;
|
||||||
context->sublevels_up--;
|
context->sublevels_up--;
|
||||||
return (Node *) newnode;
|
return (Node *) newnode;
|
||||||
}
|
}
|
||||||
|
@ -435,3 +435,17 @@ from tc;
|
|||||||
3
|
3
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Test case for sublinks pushed down into subselects via join alias expansion
|
||||||
|
--
|
||||||
|
select
|
||||||
|
(select sq1) as qq1
|
||||||
|
from
|
||||||
|
(select exists(select 1 from int4_tbl where f1 = q2) as sq1, 42 as dummy
|
||||||
|
from int8_tbl) sq0
|
||||||
|
join
|
||||||
|
int4_tbl i4 on dummy = i4.f1;
|
||||||
|
qq1
|
||||||
|
-----
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
@ -277,3 +277,15 @@ select
|
|||||||
( select min(tb.id) from tb
|
( select min(tb.id) from tb
|
||||||
where tb.aval = (select ta.val from ta where ta.id = tc.aid) ) as min_tb_id
|
where tb.aval = (select ta.val from ta where ta.id = tc.aid) ) as min_tb_id
|
||||||
from tc;
|
from tc;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Test case for sublinks pushed down into subselects via join alias expansion
|
||||||
|
--
|
||||||
|
|
||||||
|
select
|
||||||
|
(select sq1) as qq1
|
||||||
|
from
|
||||||
|
(select exists(select 1 from int4_tbl where f1 = q2) as sq1, 42 as dummy
|
||||||
|
from int8_tbl) sq0
|
||||||
|
join
|
||||||
|
int4_tbl i4 on dummy = i4.f1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user