mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-02 13:51:27 +02:00
Repair bug reported by Wickstrom: backend would crash if WHERE clause
contained a sub-SELECT nested within an AND/OR tree that cnfify() thought it should rearrange. Same physical sub-SELECT node could end up linked into multiple places in resulting expression tree. This is harmless for most node types, but not for SubLink. Repair bug by making physical copies of subexpressions that get logically duplicated by cnfify(). Also, tweak the heuristic that decides whether it's a good idea to do cnfify() --- we don't really want that to happen when it would cause multiple copies of a subselect to be generated, I think.
This commit is contained in:
parent
2e67ecaf6f
commit
9d91db4fde
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.35 2000/04/12 17:15:22 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.36 2000/04/14 00:19:16 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -136,6 +136,13 @@ make_subplan(SubLink *slink)
|
|||||||
|
|
||||||
PlannerQueryLevel++; /* we become child */
|
PlannerQueryLevel++; /* we become child */
|
||||||
|
|
||||||
|
/* Check to see if this node was already processed; if so we have
|
||||||
|
* trouble. Someday should change tree representation so that we can
|
||||||
|
* cope with multiple links to the same subquery, but for now...
|
||||||
|
*/
|
||||||
|
if (subquery == NULL)
|
||||||
|
elog(ERROR, "make_subplan: invalid expression structure (subquery already processed?)");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For an EXISTS subplan, tell lower-level planner to expect that only
|
* For an EXISTS subplan, tell lower-level planner to expect that only
|
||||||
* the first tuple will be retrieved. For ALL and ANY subplans, we
|
* the first tuple will be retrieved. For ALL and ANY subplans, we
|
||||||
@ -194,7 +201,7 @@ make_subplan(SubLink *slink)
|
|||||||
node->plan_id = PlannerPlanId++;
|
node->plan_id = PlannerPlanId++;
|
||||||
node->rtable = subquery->rtable;
|
node->rtable = subquery->rtable;
|
||||||
node->sublink = slink;
|
node->sublink = slink;
|
||||||
slink->subselect = NULL; /* cool ?! */
|
slink->subselect = NULL; /* cool ?! see error check above! */
|
||||||
|
|
||||||
/* make parParam list of params coming from current query level */
|
/* make parParam list of params coming from current query level */
|
||||||
foreach(lst, plan->extParam)
|
foreach(lst, plan->extParam)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.24 2000/04/12 17:15:23 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.25 2000/04/14 00:19:17 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -656,15 +656,26 @@ or_normalize(List *orlist)
|
|||||||
foreach(temp, distributable->args)
|
foreach(temp, distributable->args)
|
||||||
{
|
{
|
||||||
Expr *andclause = lfirst(temp);
|
Expr *andclause = lfirst(temp);
|
||||||
|
List *neworlist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are going to insert the orlist into multiple places in the
|
||||||
|
* result expression. For most expression types, it'd be OK to
|
||||||
|
* just have multiple links to the same subtree, but this fails
|
||||||
|
* badly for SubLinks (and perhaps other cases?). For safety,
|
||||||
|
* we make a distinct copy for each place the orlist is inserted.
|
||||||
|
*/
|
||||||
|
if (lnext(temp) == NIL)
|
||||||
|
neworlist = orlist; /* can use original tree at the end */
|
||||||
|
else
|
||||||
|
neworlist = copyObject(orlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pull_ors is needed here in case andclause has a top-level OR.
|
* pull_ors is needed here in case andclause has a top-level OR.
|
||||||
* Then we recursively apply or_normalize, since there might be an
|
* Then we recursively apply or_normalize, since there might be an
|
||||||
* AND subclause in the resulting OR-list. Note: we rely on
|
* AND subclause in the resulting OR-list.
|
||||||
* pull_ors to build a fresh list, and not damage the given
|
|
||||||
* orlist.
|
|
||||||
*/
|
*/
|
||||||
andclause = or_normalize(pull_ors(lcons(andclause, orlist)));
|
andclause = or_normalize(pull_ors(lcons(andclause, neworlist)));
|
||||||
andclauses = lappend(andclauses, andclause);
|
andclauses = lappend(andclauses, andclause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,15 +784,26 @@ and_normalize(List *andlist)
|
|||||||
foreach(temp, distributable->args)
|
foreach(temp, distributable->args)
|
||||||
{
|
{
|
||||||
Expr *orclause = lfirst(temp);
|
Expr *orclause = lfirst(temp);
|
||||||
|
List *newandlist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are going to insert the andlist into multiple places in the
|
||||||
|
* result expression. For most expression types, it'd be OK to
|
||||||
|
* just have multiple links to the same subtree, but this fails
|
||||||
|
* badly for SubLinks (and perhaps other cases?). For safety,
|
||||||
|
* we make a distinct copy for each place the andlist is inserted.
|
||||||
|
*/
|
||||||
|
if (lnext(temp) == NIL)
|
||||||
|
newandlist = andlist; /* can use original tree at the end */
|
||||||
|
else
|
||||||
|
newandlist = copyObject(andlist);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pull_ands is needed here in case orclause has a top-level AND.
|
* pull_ands is needed here in case orclause has a top-level AND.
|
||||||
* Then we recursively apply and_normalize, since there might be
|
* Then we recursively apply and_normalize, since there might be
|
||||||
* an OR subclause in the resulting AND-list. Note: we rely on
|
* an OR subclause in the resulting AND-list.
|
||||||
* pull_ands to build a fresh list, and not damage the given
|
|
||||||
* andlist.
|
|
||||||
*/
|
*/
|
||||||
orclause = and_normalize(pull_ands(lcons(orclause, andlist)));
|
orclause = and_normalize(pull_ands(lcons(orclause, newandlist)));
|
||||||
orclauses = lappend(orclauses, orclause);
|
orclauses = lappend(orclauses, orclause);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,6 +954,17 @@ count_bool_nodes(Expr *qual,
|
|||||||
count_bool_nodes(get_notclausearg(qual),
|
count_bool_nodes(get_notclausearg(qual),
|
||||||
nodes, cnfnodes, dnfnodes);
|
nodes, cnfnodes, dnfnodes);
|
||||||
}
|
}
|
||||||
|
else if (contain_subplans((Node *) qual))
|
||||||
|
{
|
||||||
|
/* charge extra for subexpressions containing sub-SELECTs,
|
||||||
|
* to discourage us from rearranging them in a way that might
|
||||||
|
* generate N copies of a subselect rather than one. The magic
|
||||||
|
* constant here interacts with the "4x maximum growth" heuristic
|
||||||
|
* in canonicalize_qual().
|
||||||
|
*/
|
||||||
|
*nodes = 1.0;
|
||||||
|
*cnfnodes = *dnfnodes = 25.0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* anything else counts 1 for my purposes */
|
/* anything else counts 1 for my purposes */
|
||||||
|
Loading…
Reference in New Issue
Block a user