mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08: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
97f29c865f
commit
1cf269cf99
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.54 2003/08/08 21:41:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.54.4.1 2010/07/08 00:14:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -51,6 +51,8 @@ typedef struct
|
||||
{
|
||||
Query *root;
|
||||
int sublevels_up;
|
||||
bool possible_sublink; /* could aliases include a SubLink? */
|
||||
bool inserted_sublink; /* have we inserted a SubLink? */
|
||||
} flatten_join_alias_vars_context;
|
||||
|
||||
static bool pull_varnos_walker(Node *node,
|
||||
@ -488,6 +490,14 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
||||
* relation variables instead. This allows quals involving such vars to be
|
||||
* pushed down.
|
||||
*
|
||||
* 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
|
||||
* to be applied directly to a Query node.
|
||||
*/
|
||||
@ -498,6 +508,10 @@ flatten_join_alias_vars(Query *root, Node *node)
|
||||
|
||||
context.root = root;
|
||||
context.sublevels_up = 0;
|
||||
/* flag whether join aliases could possibly contain SubLinks */
|
||||
context.possible_sublink = root->hasSubLinks;
|
||||
/* if hasSubLinks is already true, no need to work hard */
|
||||
context.inserted_sublink = root->hasSubLinks;
|
||||
|
||||
return flatten_join_alias_vars_mutator(node, &context);
|
||||
}
|
||||
@ -533,8 +547,15 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
newvar = copyObject(newvar);
|
||||
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
@ -559,12 +580,17 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
{
|
||||
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
||||
Query *newnode;
|
||||
bool save_inserted_sublink;
|
||||
|
||||
context->sublevels_up++;
|
||||
save_inserted_sublink = context->inserted_sublink;
|
||||
context->inserted_sublink = ((Query *) node)->hasSubLinks;
|
||||
newnode = query_tree_mutator((Query *) node,
|
||||
flatten_join_alias_vars_mutator,
|
||||
(void *) context,
|
||||
QTW_IGNORE_JOINALIASES);
|
||||
newnode->hasSubLinks |= context->inserted_sublink;
|
||||
context->inserted_sublink = save_inserted_sublink;
|
||||
context->sublevels_up--;
|
||||
return (Node *) newnode;
|
||||
}
|
||||
|
@ -201,3 +201,17 @@ select count(distinct ss.ten) from
|
||||
10
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- 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)
|
||||
|
||||
|
@ -93,3 +93,15 @@ select count(*) from
|
||||
select count(distinct ss.ten) from
|
||||
(select ten from tenk1 a
|
||||
where unique1 IN (select distinct hundred from tenk1 b)) ss;
|
||||
|
||||
--
|
||||
-- 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…
Reference in New Issue
Block a user