diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 3493bfda245..373b05d42fe 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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 */ + /* 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 * 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->rtable = subquery->rtable; 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 */ foreach(lst, plan->extParam) diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index fae694dc264..fed6f66f6a1 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -8,7 +8,7 @@ * * * 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) { 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. * Then we recursively apply or_normalize, since there might be an - * AND subclause in the resulting OR-list. Note: we rely on - * pull_ors to build a fresh list, and not damage the given - * orlist. + * AND subclause in the resulting OR-list. */ - andclause = or_normalize(pull_ors(lcons(andclause, orlist))); + andclause = or_normalize(pull_ors(lcons(andclause, neworlist))); andclauses = lappend(andclauses, andclause); } @@ -773,15 +784,26 @@ and_normalize(List *andlist) foreach(temp, distributable->args) { 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. * Then we recursively apply and_normalize, since there might be - * an OR subclause in the resulting AND-list. Note: we rely on - * pull_ands to build a fresh list, and not damage the given - * andlist. + * an OR subclause in the resulting AND-list. */ - orclause = and_normalize(pull_ands(lcons(orclause, andlist))); + orclause = and_normalize(pull_ands(lcons(orclause, newandlist))); orclauses = lappend(orclauses, orclause); } @@ -932,6 +954,17 @@ count_bool_nodes(Expr *qual, count_bool_nodes(get_notclausearg(qual), 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 { /* anything else counts 1 for my purposes */