diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 3b8981021a..76a16cd833 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.137 2003/01/13 00:29:25 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.138 2003/01/13 18:10:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -777,7 +777,7 @@ preprocess_expression(Query *parse, Node *expr, int kind) /* Expand SubLinks to SubPlans */ if (parse->hasSubLinks) - expr = SS_process_sublinks(expr); + expr = SS_process_sublinks(expr, (kind != EXPRKIND_TARGET)); /* Replace uplevel vars with Param nodes */ if (PlannerQueryLevel > 1) diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index c76d67b93e..1b5c72e163 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.87 2003/01/10 21:08:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.88 2003/01/13 18:10:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,7 +42,6 @@ typedef struct static void fix_expr_references(Plan *plan, Node *node); static bool fix_expr_references_walker(Node *node, void *context); -static void mark_qual_expressions(List *quals); static void set_join_references(Join *join, List *rtable); static void set_uppernode_references(Plan *plan, Index subvarno); static Node *join_references_mutator(Node *node, @@ -89,12 +88,10 @@ set_plan_references(Plan *plan, List *rtable) case T_SeqScan: fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); break; case T_IndexScan: fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, (Node *) ((IndexScan *) plan)->indxqual); fix_expr_references(plan, @@ -103,7 +100,6 @@ set_plan_references(Plan *plan, List *rtable) case T_TidScan: fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, (Node *) ((TidScan *) plan)->tideval); break; @@ -118,7 +114,6 @@ set_plan_references(Plan *plan, List *rtable) */ fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); /* Recurse into subplan too */ rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid, @@ -134,7 +129,6 @@ set_plan_references(Plan *plan, List *rtable) fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid, rtable); Assert(rte->rtekind == RTE_FUNCTION); @@ -145,17 +139,13 @@ set_plan_references(Plan *plan, List *rtable) set_join_references((Join *) plan, rtable); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); - mark_qual_expressions(((Join *) plan)->joinqual); break; case T_MergeJoin: set_join_references((Join *) plan, rtable); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); - mark_qual_expressions(((Join *) plan)->joinqual); fix_expr_references(plan, (Node *) ((MergeJoin *) plan)->mergeclauses); break; @@ -163,9 +153,7 @@ set_plan_references(Plan *plan, List *rtable) set_join_references((Join *) plan, rtable); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); - mark_qual_expressions(((Join *) plan)->joinqual); fix_expr_references(plan, (Node *) ((HashJoin *) plan)->hashclauses); break; @@ -192,7 +180,6 @@ set_plan_references(Plan *plan, List *rtable) set_uppernode_references(plan, (Index) 0); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); break; case T_Result: @@ -206,9 +193,7 @@ set_plan_references(Plan *plan, List *rtable) set_uppernode_references(plan, (Index) OUTER); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); - mark_qual_expressions(plan->qual); fix_expr_references(plan, ((Result *) plan)->resconstantqual); - mark_qual_expressions((List *) ((Result *) plan)->resconstantqual); break; case T_Append: @@ -283,28 +268,6 @@ fix_expr_references_walker(Node *node, void *context) return expression_tree_walker(node, fix_expr_references_walker, context); } -/* - * mark_qual_expressions - * Do final cleanup on qualifier expressions (not targetlists!) - * - * SubPlans appearing at the top level of a qual expression are marked - * to indicate that they need not distinguish UNKNOWN (null) from FALSE - * results; this can save processing time in some cases. - */ -static void -mark_qual_expressions(List *quals) -{ - List *qual; - - foreach(qual, quals) - { - Node *node = lfirst(qual); - - if (IsA(node, SubPlan)) - ((SubPlan *) node)->unknownEqFalse = true; - } -} - /* * set_join_references * Modifies the target list of a join node to reference its subplans, diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 42da081e05..3c72199777 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.65 2003/01/13 00:29:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.66 2003/01/13 18:10:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -65,7 +65,7 @@ static List *convert_sublink_opers(List *lefthand, List *operOids, List *targetlist, List **paramIds); static bool subplan_is_hashable(SubLink *slink, SubPlan *node); static Node *replace_correlation_vars_mutator(Node *node, void *context); -static Node *process_sublinks_mutator(Node *node, void *context); +static Node *process_sublinks_mutator(Node *node, bool *isTopQual); static bool finalize_primnode(Node *node, finalize_primnode_results *results); @@ -159,7 +159,8 @@ generate_new_param(Oid paramtype, int32 paramtypmod) * Convert a bare SubLink (as created by the parser) into a SubPlan. * * We are given the raw SubLink and the already-processed lefthand argument - * list (use this instead of the SubLink's own field). + * list (use this instead of the SubLink's own field). We are also told if + * this expression appears at top level of a WHERE/HAVING qual. * * The result is whatever we need to substitute in place of the SubLink * node in the executable expression. This will be either the SubPlan @@ -168,7 +169,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod) * containing InitPlan Param nodes. */ static Node * -make_subplan(SubLink *slink, List *lefthand) +make_subplan(SubLink *slink, List *lefthand, bool isTopQual) { SubPlan *node = makeNode(SubPlan); Query *subquery = (Query *) (slink->subselect); @@ -232,7 +233,8 @@ make_subplan(SubLink *slink, List *lefthand) node->exprs = NIL; node->paramIds = NIL; node->useHashTable = false; - node->unknownEqFalse = false; + /* At top level of a qual, can treat UNKNOWN the same as FALSE */ + node->unknownEqFalse = isTopQual; node->setParam = NIL; node->parParam = NIL; node->args = NIL; @@ -589,17 +591,23 @@ replace_correlation_vars_mutator(Node *node, void *context) /* * Expand SubLinks to SubPlans in the given expression. + * + * The isQual argument tells whether or not this expression is a WHERE/HAVING + * qualifier expression. If it is, any sublinks appearing at top level need + * not distinguish FALSE from UNKNOWN return values. */ Node * -SS_process_sublinks(Node *expr) +SS_process_sublinks(Node *expr, bool isQual) { - /* No setup needed for tree walk, so away we go */ - return process_sublinks_mutator(expr, NULL); + /* The only context needed is the initial are-we-in-a-qual flag */ + return process_sublinks_mutator(expr, &isQual); } static Node * -process_sublinks_mutator(Node *node, void *context) +process_sublinks_mutator(Node *node, bool *isTopQual) { + bool locTopQual; + if (node == NULL) return NULL; if (IsA(node, SubLink)) @@ -610,12 +618,13 @@ process_sublinks_mutator(Node *node, void *context) /* * First, recursively process the lefthand-side expressions, if any. */ + locTopQual = false; lefthand = (List *) - process_sublinks_mutator((Node *) sublink->lefthand, context); + process_sublinks_mutator((Node *) sublink->lefthand, &locTopQual); /* * Now build the SubPlan node and make the expr to return. */ - return make_subplan(sublink, lefthand); + return make_subplan(sublink, lefthand, *isTopQual); } /* @@ -626,9 +635,18 @@ process_sublinks_mutator(Node *node, void *context) */ Assert(!is_subplan(node)); + /* + * If we recurse down through anything other than a List node, we are + * definitely not at top qual level anymore. + */ + if (IsA(node, List)) + locTopQual = *isTopQual; + else + locTopQual = false; + return expression_tree_mutator(node, process_sublinks_mutator, - context); + (void *) &locTopQual); } /* diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index b504cd7bee..8fead9929f 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -16,6 +16,6 @@ extern int PlannerPlanId; /* to assign unique ID to subquery plans */ extern List *SS_finalize_plan(Plan *plan, List *rtable); extern Node *SS_replace_correlation_vars(Node *expr); -extern Node *SS_process_sublinks(Node *expr); +extern Node *SS_process_sublinks(Node *expr, bool isQual); #endif /* SUBSELECT_H */