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);
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 */
96 i = _new_param (var, PlannerQueryLevel - var->varlevelsup);
99 retval = makeNode(Param);
100 retval->paramkind = PARAM_EXEC;
101 retval->paramid = (AttrNumber) i;
102 retval->paramtype = var->vartype;
108 _make_subplan (SubLink *slink)
110 SubPlan *node = makeNode (SubPlan);
114 List *saved_ip = PlannerInitPlan;
116 PlannerInitPlan = NULL;
118 PlannerQueryLevel++; /* we becomes child */
120 node->plan = plan = union_planner ((Query*) slink->subselect);
123 * Assign subPlan, extParam and locParam to plan nodes.
124 * At the moment, SS_finalize_plan doesn't handle initPlan-s
125 * and so we assigne them to the topmost plan node and take
126 * care about its extParam too.
128 (void) SS_finalize_plan (plan);
129 plan->initPlan = PlannerInitPlan;
131 /* Get extParam from InitPlan-s */
132 foreach (lst, PlannerInitPlan)
136 foreach (lp, ((SubPlan*) lfirst (lst))->plan->extParam)
138 if ( !intMember (lfirsti(lp), plan->extParam) )
139 plan->extParam = lappendi (plan->extParam, lfirsti(lp));
143 /* and now we are parent again */
144 PlannerInitPlan = saved_ip;
147 node->plan_id = PlannerPlanId++;
148 node->rtable = ((Query*) slink->subselect)->rtable;
149 node->sublink = slink;
150 slink->subselect = NULL; /* cool ?! */
152 /* make parParam list */
153 foreach (lst, plan->extParam)
155 Var *var = nth (lfirsti(lst), PlannerParamVar);
157 if ( var->varlevelsup == PlannerQueryLevel )
158 node->parParam = lappendi (node->parParam, lfirsti(lst));
162 * Un-correlated or undirect correlated plans of EXISTS or EXPR
163 * types can be used as initPlans...
165 if ( node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK )
169 /* transform right side of all sublink Oper-s into Param */
170 foreach (lst, slink->oper)
172 List *rside = lnext(((Expr*) lfirst(lst))->args);
173 TargetEntry *te = nth (i, plan->targetlist);
174 Var *var = makeVar (0, 0, te->resdom->restype,
175 te->resdom->restypmod,
176 PlannerQueryLevel, 0, 0);
177 Param *prm = makeNode(Param);
179 prm->paramkind = PARAM_EXEC;
180 prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel);
181 prm->paramtype = var->vartype;
183 node->setParam = lappendi (node->setParam, prm->paramid);
187 PlannerInitPlan = lappend (PlannerInitPlan, node);
189 result = (Node*) ((slink->useor) ? make_orclause (slink->oper) :
190 make_andclause (slink->oper));
192 result = (Node*) lfirst (slink->oper);
194 else if ( node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK )
196 Var *var = makeVar (0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0);
197 Param *prm = makeNode(Param);
199 prm->paramkind = PARAM_EXEC;
200 prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel);
201 prm->paramtype = var->vartype;
202 node->setParam = lappendi (node->setParam, prm->paramid);
204 PlannerInitPlan = lappend (PlannerInitPlan, node);
205 result = (Node*) prm;
207 else /* make expression of SUBPLAN type */
209 Expr *expr = makeNode (Expr);
213 expr->typeOid = BOOLOID;
214 expr->opType = SUBPLAN_EXPR;
215 expr->oper = (Node*) node;
218 * Make expr->args from parParam. Left sides of sublink Oper-s
219 * are handled by optimizer directly...
220 * Also, transform right side of sublink Oper-s into Const.
222 foreach (lst, node->parParam)
224 Var *var = nth (lfirsti (lst), PlannerParamVar);
226 var = (Var*) copyObject (var);
227 var->varlevelsup = 0;
228 args = lappend (args, var);
230 foreach (lst, slink->oper)
232 List *rside = lnext(((Expr*) lfirst(lst))->args);
233 TargetEntry *te = nth (i, plan->targetlist);
234 Const *con = makeConst (te->resdom->restype,
235 0, 0, true, 0, 0, 0);
240 result = (Node*) expr;
248 set_unioni (List *l1, List *l2)
255 return (nconc (l1, set_differencei (l2, l1)));
259 _finalize_primnode (void *expr, List **subplan)
266 if (IsA (expr, Param))
268 if ( ((Param*) expr)->paramkind == PARAM_EXEC )
269 return (lconsi (((Param*) expr)->paramid, (List*) NULL));
271 else if (single_node(expr))
273 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, Aggreg))
286 return (_finalize_primnode (((Aggreg *) 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)
326 if (IsA (expr, List))
329 foreach (le, (List*) expr)
330 lfirst(le) = SS_replace_correlation_vars ((Node*) lfirst(le));
332 else if (IsA (expr, Var))
334 if ( ((Var*) expr)->varlevelsup > 0 )
336 Assert (((Var*) expr)->varlevelsup < PlannerQueryLevel);
337 expr = (Node*) _replace_var ((Var*) expr);
340 else if (IsA (expr, Iter))
342 ((Iter*) expr)->iterexpr =
343 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, Aggreg))
352 ((Aggreg *) expr)->target =
353 SS_replace_correlation_vars ((Node*) ((Aggreg *) expr)->target);
354 else if (IsA (expr, ArrayRef))
356 ((ArrayRef *) expr)->refupperindexpr = (List*)
357 SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refupperindexpr);
358 ((ArrayRef *) expr)->reflowerindexpr = (List*)
359 SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->reflowerindexpr);
360 ((ArrayRef *) expr)->refexpr =
361 SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refexpr);
362 ((ArrayRef *) expr)->refassgnexpr =
363 SS_replace_correlation_vars (((ArrayRef *) expr)->refassgnexpr);
365 else if (IsA (expr, TargetEntry))
366 ((TargetEntry*) expr)->expr =
367 SS_replace_correlation_vars ((Node*) ((TargetEntry*) expr)->expr);
368 else if (IsA (expr, SubLink))
372 foreach (le, ((SubLink*) expr)->oper) /* left sides only */
374 List *oparg = ((Expr*) lfirst (le))->args;
376 lfirst (oparg) = (List*)
377 SS_replace_correlation_vars ((Node*) lfirst (oparg));
379 ((SubLink*) expr)->lefthand = (List*)
380 SS_replace_correlation_vars ((Node*) ((SubLink*) expr)->lefthand);
383 elog (NOTICE, "SS_replace_correlation_vars: can't handle node %d",
390 SS_process_sublinks (Node *expr)
394 if (IsA (expr, List))
397 foreach (le, (List*) expr)
398 lfirst(le) = SS_process_sublinks ((Node*) lfirst(le));
400 else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
401 not_clause (expr) || is_funcclause(expr))
402 ((Expr *) expr)->args = (List*)
403 SS_process_sublinks ((Node*) ((Expr *) expr)->args);
404 else if (IsA (expr, SubLink)) /* got it! */
405 expr = _make_subplan ((SubLink*) expr);
411 SS_finalize_plan (Plan *plan)
413 List *extParam = NULL;
414 List *locParam = NULL;
415 List *subPlan = NULL;
422 param_list = _finalize_primnode (plan->targetlist, &subPlan);
423 Assert (subPlan == NULL);
425 switch (nodeTag(plan))
428 param_list = set_unioni (param_list,
429 _finalize_primnode (((Result*) plan)->resconstantqual, &subPlan));
433 foreach (lst, ((Append*) plan)->unionplans)
434 param_list = set_unioni (param_list,
435 SS_finalize_plan ((Plan*) lfirst (lst)));
439 param_list = set_unioni (param_list,
440 _finalize_primnode (((IndexScan*) plan)->indxqual, &subPlan));
441 Assert (subPlan == NULL);
445 param_list = set_unioni (param_list,
446 _finalize_primnode (((MergeJoin*) plan)->mergeclauses, &subPlan));
447 Assert (subPlan == NULL);
451 param_list = set_unioni (param_list,
452 _finalize_primnode (((HashJoin*) plan)->hashclauses, &subPlan));
453 Assert (subPlan == NULL);
457 param_list = set_unioni (param_list,
458 _finalize_primnode (((Hash*) plan)->hashkey, &subPlan));
459 Assert (subPlan == NULL);
463 param_list = set_unioni (param_list,
464 _finalize_primnode (((Agg*) plan)->aggs, &subPlan));
465 Assert (subPlan == NULL);
476 elog(ERROR, "SS_finalize_plan: node %d unsupported", nodeTag(plan));
480 param_list = set_unioni (param_list, _finalize_primnode (plan->qual, &subPlan));
481 param_list = set_unioni (param_list, SS_finalize_plan (plan->lefttree));
482 param_list = set_unioni (param_list, SS_finalize_plan (plan->righttree));
484 foreach (lst, param_list)
486 Var *var = nth (lfirsti(lst), PlannerParamVar);
488 if ( var->varlevelsup < PlannerQueryLevel )
489 extParam = lappendi (extParam, lfirsti(lst));
490 else if ( var->varlevelsup > PlannerQueryLevel )
491 elog (ERROR, "SS_finalize_plan: plan shouldn't reference subplan' variable");
494 Assert (var->varno == 0 && var->varattno == 0);
495 locParam = lappendi (locParam, lfirsti(lst));
499 plan->extParam = extParam;
500 plan->locParam = locParam;
501 plan->subPlan = subPlan;
507 List *SS_pull_subplan (void *expr);
510 SS_pull_subplan (void *expr)
514 if ( expr == NULL || single_node(expr) )
517 if (IsA (expr, List))
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, Aggreg))
529 return (SS_pull_subplan (((Aggreg *) 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",