1 /*-------------------------------------------------------------------------
4 * Planning routines for subselects and parameters.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.33 2000/03/21 05:12:02 tgl Exp $
12 *-------------------------------------------------------------------------
16 #include "catalog/pg_operator.h"
17 #include "catalog/pg_type.h"
18 #include "nodes/makefuncs.h"
19 #include "nodes/nodeFuncs.h"
20 #include "optimizer/clauses.h"
21 #include "optimizer/cost.h"
22 #include "optimizer/planmain.h"
23 #include "optimizer/planner.h"
24 #include "optimizer/subselect.h"
25 #include "parser/parse_expr.h"
26 #include "parser/parse_node.h"
27 #include "parser/parse_oper.h"
28 #include "utils/lsyscache.h"
31 Index PlannerQueryLevel; /* level of current query */
32 List *PlannerInitPlan; /* init subplans for current query */
33 List *PlannerParamVar; /* to get Var from Param->paramid */
34 int PlannerPlanId; /* to assign unique ID to subquery plans */
36 /*--------------------
37 * PlannerParamVar is a list of Var nodes, wherein the n'th entry
38 * (n counts from 0) corresponds to Param->paramid = n. The Var nodes
39 * are ordinary except for one thing: their varlevelsup field does NOT
40 * have the usual interpretation of "subplan levels out from current".
41 * Instead, it contains the absolute plan level, with the outermost
42 * plan being level 1 and nested plans having higher level numbers.
43 * This nonstandardness is useful because we don't have to run around
44 * and update the list elements when we enter or exit a subplan
45 * recursion level. But we must pay attention not to confuse this
46 * meaning with the normal meaning of varlevelsup.
52 * Create a new entry in the PlannerParamVar list, and return its index.
54 * var contains the data to be copied, except for varlevelsup which
55 * is set from the absolute level value given by varlevel.
58 new_param(Var *var, Index varlevel)
60 Var *paramVar = (Var *) copyObject(var);
62 paramVar->varlevelsup = varlevel;
64 PlannerParamVar = lappend(PlannerParamVar, paramVar);
66 return length(PlannerParamVar) - 1;
70 * Generate a Param node to replace the given Var,
71 * which is expected to have varlevelsup > 0 (ie, it is not local).
81 Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);
82 varlevel = PlannerQueryLevel - var->varlevelsup;
85 * If there's already a PlannerParamVar entry for this same Var,
86 * just use it. NOTE: in situations involving UNION or inheritance,
87 * it is possible for the same varno/varlevel to refer to different RTEs
88 * in different parts of the parsetree, so that different fields might
89 * end up sharing the same Param number. As long as we check the vartype
90 * as well, I believe that this sort of aliasing will cause no trouble.
91 * The correct field should get stored into the Param slot at execution
92 * in each part of the tree.
95 foreach(ppv, PlannerParamVar)
97 Var *pvar = lfirst(ppv);
99 if (pvar->varno == var->varno &&
100 pvar->varattno == var->varattno &&
101 pvar->varlevelsup == varlevel &&
102 pvar->vartype == var->vartype)
109 /* Nope, so make a new one */
110 i = new_param(var, varlevel);
113 retval = makeNode(Param);
114 retval->paramkind = PARAM_EXEC;
115 retval->paramid = (AttrNumber) i;
116 retval->paramtype = var->vartype;
122 * Convert a bare SubLink (as created by the parser) into a SubPlan.
125 make_subplan(SubLink *slink)
127 SubPlan *node = makeNode(SubPlan);
128 Query *subquery = (Query *) (slink->subselect);
129 double tuple_fraction;
133 List *saved_ip = PlannerInitPlan;
135 PlannerInitPlan = NULL;
137 PlannerQueryLevel++; /* we become child */
140 * For an EXISTS subplan, tell lower-level planner to expect that
141 * only the first tuple will be retrieved. For ALL and ANY subplans,
142 * we will be able to stop evaluating if the test condition fails,
143 * so very often not all the tuples will be retrieved; for lack of a
144 * better idea, specify 50% retrieval. For EXPR and MULTIEXPR subplans,
145 * use default behavior (we're only expecting one row out, anyway).
147 * NOTE: if you change these numbers, also change cost_qual_eval_walker()
148 * in path/costsize.c.
150 * XXX If an ALL/ANY subplan is uncorrelated, we may decide to materialize
151 * its result below. In that case it would've been better to specify
152 * full retrieval. At present, however, we can only detect correlation
153 * or lack of it after we've made the subplan :-(. Perhaps detection
154 * of correlation should be done as a separate step. Meanwhile, we don't
155 * want to be too optimistic about the percentage of tuples retrieved,
156 * for fear of selecting a plan that's bad for the materialization case.
158 if (slink->subLinkType == EXISTS_SUBLINK)
159 tuple_fraction = 1.0; /* just like a LIMIT 1 */
160 else if (slink->subLinkType == ALL_SUBLINK ||
161 slink->subLinkType == ANY_SUBLINK)
162 tuple_fraction = 0.5; /* 50% */
164 tuple_fraction = -1.0; /* default behavior */
166 node->plan = plan = subquery_planner(subquery, tuple_fraction);
169 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
170 * SS_finalize_plan doesn't handle initPlan-s and so we assign them
171 * to the topmost plan node and take care about its extParam too.
173 (void) SS_finalize_plan(plan);
174 plan->initPlan = PlannerInitPlan;
176 /* Create extParam list as union of InitPlan-s' lists */
177 foreach(lst, PlannerInitPlan)
181 foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)
183 if (!intMember(lfirsti(lp), plan->extParam))
184 plan->extParam = lappendi(plan->extParam, lfirsti(lp));
188 /* and now we are parent again */
189 PlannerInitPlan = saved_ip;
192 node->plan_id = PlannerPlanId++;
193 node->rtable = subquery->rtable;
194 node->sublink = slink;
195 slink->subselect = NULL; /* cool ?! */
197 /* make parParam list of params coming from current query level */
198 foreach(lst, plan->extParam)
200 Var *var = nth(lfirsti(lst), PlannerParamVar);
202 /* note varlevelsup is absolute level number */
203 if (var->varlevelsup == PlannerQueryLevel)
204 node->parParam = lappendi(node->parParam, lfirsti(lst));
208 * Un-correlated or undirect correlated plans of EXISTS, EXPR, or
209 * MULTIEXPR types can be used as initPlans. For EXISTS or EXPR,
210 * we just produce a Param referring to the result of evaluating the
211 * initPlan. For MULTIEXPR, we must build an AND or OR-clause of the
212 * individual comparison operators, using the appropriate lefthand
213 * side expressions and Params for the initPlan's target items.
215 if (node->parParam == NIL && slink->subLinkType == EXISTS_SUBLINK)
217 Var *var = makeVar(0, 0, BOOLOID, -1, 0);
218 Param *prm = makeNode(Param);
220 prm->paramkind = PARAM_EXEC;
221 prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
222 prm->paramtype = var->vartype;
223 pfree(var); /* var is only needed for new_param */
224 node->setParam = lappendi(node->setParam, prm->paramid);
225 PlannerInitPlan = lappend(PlannerInitPlan, node);
226 result = (Node *) prm;
228 else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
230 TargetEntry *te = lfirst(plan->targetlist);
231 /* need a var node just to pass to new_param()... */
232 Var *var = makeVar(0, 0, te->resdom->restype,
233 te->resdom->restypmod, 0);
234 Param *prm = makeNode(Param);
236 prm->paramkind = PARAM_EXEC;
237 prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
238 prm->paramtype = var->vartype;
239 pfree(var); /* var is only needed for new_param */
240 node->setParam = lappendi(node->setParam, prm->paramid);
241 PlannerInitPlan = lappend(PlannerInitPlan, node);
242 result = (Node *) prm;
244 else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
250 * Convert oper list of Opers into a list of Exprs, using
251 * lefthand arguments and Params representing inside results.
253 foreach(lst, slink->oper)
255 Oper *oper = (Oper *) lfirst(lst);
256 Node *lefthand = nth(i, slink->lefthand);
257 TargetEntry *te = nth(i, plan->targetlist);
258 /* need a var node just to pass to new_param()... */
259 Var *var = makeVar(0, 0, te->resdom->restype,
260 te->resdom->restypmod, 0);
261 Param *prm = makeNode(Param);
263 Form_pg_operator opform;
267 prm->paramkind = PARAM_EXEC;
268 prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
269 prm->paramtype = var->vartype;
270 pfree(var); /* var is only needed for new_param */
272 Assert(IsA(oper, Oper));
273 tup = get_operator_tuple(oper->opno);
274 Assert(HeapTupleIsValid(tup));
275 opform = (Form_pg_operator) GETSTRUCT(tup);
276 /* Note: we use make_operand in case runtime type conversion
277 * function calls must be inserted for this operator!
279 left = make_operand("", lefthand,
280 exprType(lefthand), opform->oprleft);
281 right = make_operand("", (Node *) prm,
282 prm->paramtype, opform->oprright);
283 newoper = lappend(newoper,
287 node->setParam = lappendi(node->setParam, prm->paramid);
290 slink->oper = newoper;
291 slink->lefthand = NIL;
292 PlannerInitPlan = lappend(PlannerInitPlan, node);
294 result = (Node *) ((slink->useor) ? make_orclause(newoper) :
295 make_andclause(newoper));
297 result = (Node *) lfirst(newoper);
301 Expr *expr = makeNode(Expr);
307 * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to
308 * initPlans, even when they are uncorrelated or undirect correlated,
309 * because we need to scan the output of the subplan for each outer
310 * tuple. However, we have the option to tack a MATERIAL node onto
311 * the top of an uncorrelated/undirect correlated subplan, which lets
312 * us do the work of evaluating the subplan only once. We do this
313 * if the subplan's top plan node is anything more complicated than
314 * a plain sequential scan, and we do it even for seqscan if the
315 * qual appears selective enough to eliminate many tuples.
317 if (node->parParam == NIL)
321 switch (nodeTag(plan))
324 if (plan->initPlan || plan->subPlan)
330 qualsel = clauselist_selectivity(subquery,
333 /* Is 10% selectivity a good threshold?? */
334 use_material = qualsel < 0.10;
339 /* Don't add another Material node if there's one already,
340 * nor if the top node is a Sort, since Sort materializes
341 * its output anyway. (I doubt either case can happen in
342 * practice for a subplan, but...)
344 use_material = false;
352 plan = (Plan *) make_noname(plan->targetlist,
360 * Make expression of SUBPLAN type
362 expr->typeOid = BOOLOID; /* bogus, but we don't really care */
363 expr->opType = SUBPLAN_EXPR;
364 expr->oper = (Node *) node;
367 * Make expr->args from parParam.
369 foreach(lst, node->parParam)
371 Var *var = nth(lfirsti(lst), PlannerParamVar);
373 var = (Var *) copyObject(var);
374 /* Must fix absolute-level varlevelsup from the
375 * PlannerParamVar entry. But since var is at current
376 * subplan level, this is easy:
378 var->varlevelsup = 0;
379 args = lappend(args, var);
383 * Convert oper list of Opers into a list of Exprs, using
384 * lefthand arguments and Consts representing inside results.
386 foreach(lst, slink->oper)
388 Oper *oper = (Oper *) lfirst(lst);
389 Node *lefthand = nth(i, slink->lefthand);
390 TargetEntry *te = nth(i, plan->targetlist);
393 Form_pg_operator opform;
398 * XXX really ought to fill in constlen and constbyval correctly,
399 * but right now ExecEvalExpr won't look at them...
401 con = makeConst(te->resdom->restype, 0, 0, true, 0, 0, 0);
403 Assert(IsA(oper, Oper));
404 tup = get_operator_tuple(oper->opno);
405 Assert(HeapTupleIsValid(tup));
406 opform = (Form_pg_operator) GETSTRUCT(tup);
407 /* Note: we use make_operand in case runtime type conversion
408 * function calls must be inserted for this operator!
410 left = make_operand("", lefthand,
411 exprType(lefthand), opform->oprleft);
412 right = make_operand("", (Node *) con,
413 con->consttype, opform->oprright);
414 newoper = lappend(newoper,
420 slink->oper = newoper;
421 slink->lefthand = NIL;
422 result = (Node *) expr;
428 /* this oughta be merged with LispUnioni */
431 set_unioni(List *l1, List *l2)
438 return nconc(l1, set_differencei(l2, l1));
442 * finalize_primnode: build lists of subplans and params appearing
443 * in the given expression tree. NOTE: items are added to lists passed in,
444 * so caller must initialize lists to NIL before first call!
447 typedef struct finalize_primnode_results {
448 List *subplans; /* List of subplans found in expr */
449 List *paramids; /* List of PARAM_EXEC paramids found */
450 } finalize_primnode_results;
453 finalize_primnode(Node *node, finalize_primnode_results *results)
457 if (IsA(node, Param))
459 if (((Param *) node)->paramkind == PARAM_EXEC)
461 int paramid = (int) ((Param *) node)->paramid;
463 if (! intMember(paramid, results->paramids))
464 results->paramids = lconsi(paramid, results->paramids);
466 return false; /* no more to do here */
468 if (is_subplan(node))
470 SubPlan *subplan = (SubPlan *) ((Expr *) node)->oper;
473 /* Add subplan to subplans list */
474 results->subplans = lappend(results->subplans, subplan);
475 /* Check extParam list for params to add to paramids */
476 foreach(lst, subplan->plan->extParam)
478 int paramid = lfirsti(lst);
479 Var *var = nth(paramid, PlannerParamVar);
481 /* note varlevelsup is absolute level number */
482 if (var->varlevelsup < PlannerQueryLevel &&
483 ! intMember(paramid, results->paramids))
484 results->paramids = lconsi(paramid, results->paramids);
486 /* fall through to recurse into subplan args */
488 return expression_tree_walker(node, finalize_primnode,
493 * Replace correlation vars (uplevel vars) with Params.
496 static Node *replace_correlation_vars_mutator(Node *node, void *context);
499 SS_replace_correlation_vars(Node *expr)
501 /* No setup needed for tree walk, so away we go */
502 return replace_correlation_vars_mutator(expr, NULL);
506 replace_correlation_vars_mutator(Node *node, void *context)
512 if (((Var *) node)->varlevelsup > 0)
513 return (Node *) replace_var((Var *) node);
515 return expression_tree_mutator(node,
516 replace_correlation_vars_mutator,
521 * Expand SubLinks to SubPlans in the given expression.
524 static Node *process_sublinks_mutator(Node *node, void *context);
527 SS_process_sublinks(Node *expr)
529 /* No setup needed for tree walk, so away we go */
530 return process_sublinks_mutator(expr, NULL);
534 process_sublinks_mutator(Node *node, void *context)
538 if (IsA(node, SubLink))
540 SubLink *sublink = (SubLink *) node;
542 /* First, scan the lefthand-side expressions, if any.
543 * This is a tad klugy since we modify the input SubLink node,
544 * but that should be OK (make_subplan does it too!)
546 sublink->lefthand = (List *)
547 process_sublinks_mutator((Node *) sublink->lefthand, context);
548 /* Now build the SubPlan node and make the expr to return */
549 return make_subplan(sublink);
552 * Note that we will never see a SubPlan expression in the input
553 * (since this is the very routine that creates 'em to begin with).
554 * So the code in expression_tree_mutator() that might do
555 * inappropriate things with SubPlans or SubLinks will not be
558 Assert(! is_subplan(node));
560 return expression_tree_mutator(node,
561 process_sublinks_mutator,
566 SS_finalize_plan(Plan *plan)
568 List *extParam = NIL;
569 List *locParam = NIL;
570 finalize_primnode_results results;
576 results.subplans = NIL; /* initialize lists to NIL */
577 results.paramids = NIL;
579 * When we call finalize_primnode, results.paramids lists are
580 * automatically merged together. But when recursing to self,
581 * we have to do it the hard way. We want the paramids list
582 * to include params in subplans as well as at this level.
583 * (We don't care about finding subplans of subplans, though.)
586 /* Find params and subplans in targetlist and qual */
587 finalize_primnode((Node *) plan->targetlist, &results);
588 finalize_primnode((Node *) plan->qual, &results);
590 /* Check additional node-type-specific fields */
591 switch (nodeTag(plan))
594 finalize_primnode(((Result *) plan)->resconstantqual,
599 foreach(lst, ((Append *) plan)->appendplans)
600 results.paramids = set_unioni(results.paramids,
601 SS_finalize_plan((Plan *) lfirst(lst)));
605 finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
610 finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
615 finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
620 finalize_primnode((Node *) ((Hash *) plan)->hashkey,
625 finalize_primnode((Node *) ((TidScan *) plan)->tideval,
639 elog(ERROR, "SS_finalize_plan: node %d unsupported",
643 /* Process left and right subplans, if any */
644 results.paramids = set_unioni(results.paramids,
645 SS_finalize_plan(plan->lefttree));
646 results.paramids = set_unioni(results.paramids,
647 SS_finalize_plan(plan->righttree));
649 /* Now we have all the paramids and subplans */
651 foreach(lst, results.paramids)
653 Var *var = nth(lfirsti(lst), PlannerParamVar);
655 /* note varlevelsup is absolute level number */
656 if (var->varlevelsup < PlannerQueryLevel)
657 extParam = lappendi(extParam, lfirsti(lst));
658 else if (var->varlevelsup > PlannerQueryLevel)
659 elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan's variable");
662 Assert(var->varno == 0 && var->varattno == 0);
663 locParam = lappendi(locParam, lfirsti(lst));
667 plan->extParam = extParam;
668 plan->locParam = locParam;
669 plan->subPlan = results.subplans;
671 return results.paramids;
675 * Construct a list of all subplans found within the given node tree.
678 static bool SS_pull_subplan_walker(Node *node, List **listptr);
681 SS_pull_subplan(Node *expr)
685 SS_pull_subplan_walker(expr, &result);
690 SS_pull_subplan_walker(Node *node, List **listptr)
694 if (is_subplan(node))
696 *listptr = lappend(*listptr, ((Expr *) node)->oper);
697 /* fall through to check args to subplan */
699 return expression_tree_walker(node, SS_pull_subplan_walker,