1 /*-------------------------------------------------------------------------
5 *-------------------------------------------------------------------------
9 #include "catalog/pg_type.h"
11 #include "nodes/pg_list.h"
12 #include "nodes/plannodes.h"
13 #include "nodes/parsenodes.h"
14 #include "nodes/relation.h"
15 #include "nodes/makefuncs.h"
16 #include "nodes/nodeFuncs.h"
18 #include "optimizer/subselect.h"
19 #include "optimizer/planner.h"
20 #include "optimizer/planmain.h"
21 #include "optimizer/internal.h"
22 #include "optimizer/paths.h"
23 #include "optimizer/clauses.h"
24 #include "optimizer/keys.h"
25 #include "optimizer/tlist.h"
26 #include "optimizer/var.h"
27 #include "optimizer/cost.h"
29 int PlannerQueryLevel; /* level of current query */
30 List *PlannerVarParam; /* correlation Vars to Param mapper */
31 List *PlannerParamVar; /* to get Var from Param->paramid */
32 List *PlannerInitPlan; /* init subplans for current query */
37 _new_param(Var *var, int varlevel)
42 if (PlannerParamVar == NULL)
43 last = PlannerParamVar = makeNode(List);
46 for (last = PlannerParamVar;;)
49 if (lnext(last) == NULL)
53 lnext(last) = makeNode(List);
58 lfirst(last) = makeVar(var->varno, var->varattno, var->vartype,
59 var->vartypmod, varlevel, var->varnoold, var->varoattno);
65 _replace_var(Var *var)
67 List **rt = (List **) nth(var->varlevelsup, PlannerVarParam);
68 List *vpe = rt[var->varno - 1];
74 vpe = rt[var->varno - 1] = makeNode(List);
79 for (i = ObjectIdAttributeNumber;; i++)
81 if (i == var->varattno)
83 if (lnext(vpe) == NULL)
85 lnext(vpe) = makeNode(List);
94 if ((i = lfirsti(vpe)) < 0) /* parameter is not assigned */
95 i = _new_param(var, PlannerQueryLevel - var->varlevelsup);
97 retval = makeNode(Param);
98 retval->paramkind = PARAM_EXEC;
99 retval->paramid = (AttrNumber) i;
100 retval->paramtype = var->vartype;
106 _make_subplan(SubLink *slink)
108 SubPlan *node = makeNode(SubPlan);
112 List *saved_ip = PlannerInitPlan;
114 PlannerInitPlan = NULL;
116 PlannerQueryLevel++; /* we becomes child */
118 node->plan = plan = union_planner((Query *) slink->subselect);
121 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
122 * SS_finalize_plan doesn't handle initPlan-s and so we assigne them
123 * to the topmost plan node and take care about its extParam too.
125 (void) SS_finalize_plan(plan);
126 plan->initPlan = PlannerInitPlan;
128 /* Get extParam from InitPlan-s */
129 foreach(lst, PlannerInitPlan)
133 foreach(lp, ((SubPlan *) lfirst(lst))->plan->extParam)
135 if (!intMember(lfirsti(lp), plan->extParam))
136 plan->extParam = lappendi(plan->extParam, lfirsti(lp));
140 /* and now we are parent again */
141 PlannerInitPlan = saved_ip;
144 node->plan_id = PlannerPlanId++;
145 node->rtable = ((Query *) slink->subselect)->rtable;
146 node->sublink = slink;
147 slink->subselect = NULL; /* cool ?! */
149 /* make parParam list */
150 foreach(lst, plan->extParam)
152 Var *var = nth(lfirsti(lst), PlannerParamVar);
154 if (var->varlevelsup == PlannerQueryLevel)
155 node->parParam = lappendi(node->parParam, lfirsti(lst));
159 * Un-correlated or undirect correlated plans of EXISTS or EXPR types
160 * can be used as initPlans...
162 if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
166 /* transform right side of all sublink Oper-s into Param */
167 foreach(lst, slink->oper)
169 List *rside = lnext(((Expr *) lfirst(lst))->args);
170 TargetEntry *te = nth(i, plan->targetlist);
171 Var *var = makeVar(0, 0, te->resdom->restype,
172 te->resdom->restypmod,
173 PlannerQueryLevel, 0, 0);
174 Param *prm = makeNode(Param);
176 prm->paramkind = PARAM_EXEC;
177 prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
178 prm->paramtype = var->vartype;
180 node->setParam = lappendi(node->setParam, prm->paramid);
184 PlannerInitPlan = lappend(PlannerInitPlan, node);
186 result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
187 make_andclause(slink->oper));
189 result = (Node *) lfirst(slink->oper);
191 else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
193 Var *var = makeVar(0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0);
194 Param *prm = makeNode(Param);
196 prm->paramkind = PARAM_EXEC;
197 prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
198 prm->paramtype = var->vartype;
199 node->setParam = lappendi(node->setParam, prm->paramid);
201 PlannerInitPlan = lappend(PlannerInitPlan, node);
202 result = (Node *) prm;
205 /* make expression of SUBPLAN type */
207 Expr *expr = makeNode(Expr);
211 expr->typeOid = BOOLOID;
212 expr->opType = SUBPLAN_EXPR;
213 expr->oper = (Node *) node;
216 * Make expr->args from parParam. Left sides of sublink Oper-s are
217 * handled by optimizer directly... Also, transform right side of
218 * sublink Oper-s into Const.
220 foreach(lst, node->parParam)
222 Var *var = nth(lfirsti(lst), PlannerParamVar);
224 var = (Var *) copyObject(var);
225 var->varlevelsup = 0;
226 args = lappend(args, var);
228 foreach(lst, slink->oper)
230 List *rside = lnext(((Expr *) lfirst(lst))->args);
231 TargetEntry *te = nth(i, plan->targetlist);
232 Const *con = makeConst(te->resdom->restype,
233 0, 0, true, 0, 0, 0);
239 result = (Node *) expr;
247 set_unioni(List *l1, List *l2)
254 return nconc(l1, set_differencei(l2, l1));
258 _finalize_primnode(void *expr, List **subplan)
265 if (IsA(expr, Param))
267 if (((Param *) expr)->paramkind == PARAM_EXEC)
268 return lconsi(((Param *) expr)->paramid, (List *) NULL);
270 else if (single_node(expr))
272 else if (IsA(expr, List))
276 foreach(le, (List *) expr)
277 result = set_unioni(result,
278 _finalize_primnode(lfirst(le), subplan));
280 else if (IsA(expr, Iter))
281 return _finalize_primnode(((Iter *) expr)->iterexpr, subplan);
282 else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
283 not_clause(expr) || is_funcclause(expr))
284 return _finalize_primnode(((Expr *) expr)->args, subplan);
285 else if (IsA(expr, Aggref))
286 return _finalize_primnode(((Aggref *) expr)->target, subplan);
287 else if (IsA(expr, ArrayRef))
289 result = _finalize_primnode(((ArrayRef *) expr)->refupperindexpr, subplan);
290 result = set_unioni(result,
291 _finalize_primnode(((ArrayRef *) expr)->reflowerindexpr, subplan));
292 result = set_unioni(result,
293 _finalize_primnode(((ArrayRef *) expr)->refexpr, subplan));
294 result = set_unioni(result,
295 _finalize_primnode(((ArrayRef *) expr)->refassgnexpr, subplan));
297 else if (IsA(expr, TargetEntry))
298 return _finalize_primnode(((TargetEntry *) expr)->expr, subplan);
299 else if (is_subplan(expr))
303 *subplan = lappend(*subplan, ((Expr *) expr)->oper);
304 foreach(lst, ((SubPlan *) ((Expr *) expr)->oper)->plan->extParam)
306 Var *var = nth(lfirsti(lst), PlannerParamVar);
308 if (var->varlevelsup < PlannerQueryLevel &&
309 !intMember(lfirsti(lst), result))
310 result = lappendi(result, lfirsti(lst));
314 elog(ERROR, "_finalize_primnode: can't handle node %d",
321 SS_replace_correlation_vars(Node *expr)
330 foreach(le, (List *) expr)
331 lfirst(le) = SS_replace_correlation_vars((Node *) lfirst(le));
333 else if (IsA(expr, Var))
335 if (((Var *) expr)->varlevelsup > 0)
337 Assert(((Var *) expr)->varlevelsup < PlannerQueryLevel);
338 expr = (Node *) _replace_var((Var *) expr);
341 else if (IsA(expr, Iter))
343 ((Iter *) expr)->iterexpr = SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
345 else if (single_node(expr))
347 else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
348 not_clause(expr) || is_funcclause(expr))
349 ((Expr *) expr)->args = (List *)
350 SS_replace_correlation_vars((Node *) ((Expr *) expr)->args);
351 else if (IsA(expr, Aggref))
352 ((Aggref *) expr)->target = SS_replace_correlation_vars((Node *) ((Aggref *) expr)->target);
353 else if (IsA(expr, ArrayRef))
355 ((ArrayRef *) expr)->refupperindexpr = (List *)
356 SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refupperindexpr);
357 ((ArrayRef *) expr)->reflowerindexpr = (List *)
358 SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->reflowerindexpr);
359 ((ArrayRef *) expr)->refexpr = SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refexpr);
360 ((ArrayRef *) expr)->refassgnexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refassgnexpr);
362 else if (IsA(expr, TargetEntry))
363 ((TargetEntry *) expr)->expr = SS_replace_correlation_vars((Node *) ((TargetEntry *) expr)->expr);
364 else if (IsA(expr, SubLink))
368 foreach(le, ((SubLink *) expr)->oper) /* left sides only */
370 List *oparg = ((Expr *) lfirst(le))->args;
372 lfirst(oparg) = (List *)
373 SS_replace_correlation_vars((Node *) lfirst(oparg));
375 ((SubLink *) expr)->lefthand = (List *)
376 SS_replace_correlation_vars((Node *) ((SubLink *) expr)->lefthand);
379 elog(NOTICE, "SS_replace_correlation_vars: can't handle node %d",
386 SS_process_sublinks(Node *expr)
394 foreach(le, (List *) expr)
395 lfirst(le) = SS_process_sublinks((Node *) lfirst(le));
397 else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
398 not_clause(expr) || is_funcclause(expr))
399 ((Expr *) expr)->args = (List *)
400 SS_process_sublinks((Node *) ((Expr *) expr)->args);
401 else if (IsA(expr, SubLink))/* got it! */
403 expr = _make_subplan((SubLink *) expr);
410 SS_finalize_plan(Plan *plan)
412 List *extParam = NULL;
413 List *locParam = NULL;
414 List *subPlan = NULL;
421 param_list = _finalize_primnode(plan->targetlist, &subPlan);
422 Assert(subPlan == NULL);
424 switch (nodeTag(plan))
427 param_list = set_unioni(param_list,
428 _finalize_primnode(((Result *) plan)->resconstantqual, &subPlan));
432 foreach(lst, ((Append *) plan)->appendplans)
433 param_list = set_unioni(param_list,
434 SS_finalize_plan((Plan *) lfirst(lst)));
438 param_list = set_unioni(param_list,
439 _finalize_primnode(((IndexScan *) plan)->indxqual, &subPlan));
440 Assert(subPlan == NULL);
444 param_list = set_unioni(param_list,
445 _finalize_primnode(((MergeJoin *) plan)->mergeclauses, &subPlan));
446 Assert(subPlan == NULL);
450 param_list = set_unioni(param_list,
451 _finalize_primnode(((HashJoin *) plan)->hashclauses, &subPlan));
452 Assert(subPlan == NULL);
456 param_list = set_unioni(param_list,
457 _finalize_primnode(((Hash *) plan)->hashkey, &subPlan));
458 Assert(subPlan == NULL);
462 param_list = set_unioni(param_list,
463 _finalize_primnode(((Agg *) plan)->aggs, &subPlan));
464 Assert(subPlan == NULL);
475 elog(ERROR, "SS_finalize_plan: node %d unsupported", nodeTag(plan));
479 param_list = set_unioni(param_list, _finalize_primnode(plan->qual, &subPlan));
480 param_list = set_unioni(param_list, SS_finalize_plan(plan->lefttree));
481 param_list = set_unioni(param_list, SS_finalize_plan(plan->righttree));
483 foreach(lst, param_list)
485 Var *var = nth(lfirsti(lst), PlannerParamVar);
487 if (var->varlevelsup < PlannerQueryLevel)
488 extParam = lappendi(extParam, lfirsti(lst));
489 else if (var->varlevelsup > PlannerQueryLevel)
490 elog(ERROR, "SS_finalize_plan: plan shouldn't reference subplan' variable");
493 Assert(var->varno == 0 && var->varattno == 0);
494 locParam = lappendi(locParam, lfirsti(lst));
498 plan->extParam = extParam;
499 plan->locParam = locParam;
500 plan->subPlan = subPlan;
506 List *SS_pull_subplan(void *expr);
509 SS_pull_subplan(void *expr)
513 if (expr == NULL || single_node(expr))
520 foreach(le, (List *) expr)
521 result = nconc(result, SS_pull_subplan(lfirst(le)));
523 else if (IsA(expr, Iter))
524 return SS_pull_subplan(((Iter *) expr)->iterexpr);
525 else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
526 not_clause(expr) || is_funcclause(expr))
527 return SS_pull_subplan(((Expr *) expr)->args);
528 else if (IsA(expr, Aggref))
529 return SS_pull_subplan(((Aggref *) expr)->target);
530 else if (IsA(expr, ArrayRef))
532 result = SS_pull_subplan(((ArrayRef *) expr)->refupperindexpr);
533 result = nconc(result,
534 SS_pull_subplan(((ArrayRef *) expr)->reflowerindexpr));
535 result = nconc(result,
536 SS_pull_subplan(((ArrayRef *) expr)->refexpr));
537 result = nconc(result,
538 SS_pull_subplan(((ArrayRef *) expr)->refassgnexpr));
540 else if (IsA(expr, TargetEntry))
541 return SS_pull_subplan(((TargetEntry *) expr)->expr);
542 else if (is_subplan(expr))
543 return lcons(((Expr *) expr)->oper, NULL);
545 elog(ERROR, "SS_pull_subplan: can't handle node %d",