diff options
author | Vadim B. Mikheev <vadim4o@yahoo.com> | 1998-02-13 03:37:04 +0000 |
---|---|---|
committer | Vadim B. Mikheev <vadim4o@yahoo.com> | 1998-02-13 03:37:04 +0000 |
commit | 4a6e3a6a9fa18e01d6ae65015e55a42f36030d0d (patch) | |
tree | 6ec2fc20051c9097ff94f4778d6cd660b6c66879 /src/backend/optimizer/plan/subselect.c | |
parent | a3f1c3673fb56752ebb1c6d9bab0706e7f8ae7ac (diff) | |
download | postgresql-4a6e3a6a9fa18e01d6ae65015e55a42f36030d0d.tar.gz postgresql-4a6e3a6a9fa18e01d6ae65015e55a42f36030d0d.zip |
Old planner() becomes union_planner(); new planner() makes initialization
of some global variables to support subselects and calls union_planner().
Calls to SS_replace_correlation_vars() and SS_process_sublinks() in
query_planner() before planning.
Get rid of #ifdef INDEXSCAN_PATCH in createplan.c.
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c new file mode 100644 index 00000000000..4d4378780c2 --- /dev/null +++ b/src/backend/optimizer/plan/subselect.c @@ -0,0 +1,549 @@ +/*------------------------------------------------------------------------- + * + * subselect.c-- + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "catalog/pg_type.h" + +#include "nodes/pg_list.h" +#include "nodes/plannodes.h" +#include "nodes/parsenodes.h" +#include "nodes/relation.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" + +#include "optimizer/subselect.h" +#include "optimizer/planner.h" +#include "optimizer/planmain.h" +#include "optimizer/internal.h" +#include "optimizer/paths.h" +#include "optimizer/clauses.h" +#include "optimizer/keys.h" +#include "optimizer/tlist.h" +#include "optimizer/var.h" +#include "optimizer/cost.h" + +int PlannerQueryLevel; /* level of current query */ +List *PlannerVarParam; /* correlation Vars to Param mapper */ +List *PlannerParamVar; /* to get Var from Param->paramid */ +List *PlannerInitPlan; /* init subplans for current query */ +int PlannerPlanId; + + +static int +_new_param (Var *var, int varlevel) +{ + List *last; + int i = 0; + + if ( PlannerParamVar == NULL ) + last = PlannerParamVar = makeNode(List); + else + { + for (last = PlannerParamVar; ; ) + { + i++; + if ( lnext(last) == NULL ) + break; + last = lnext(last); + } + lnext(last) = makeNode(List); + last = lnext(last); + } + + lnext(last) = NULL; + lfirst(last) = makeVar (var->varno, var->varattno, var->vartype, + var->vartypmod, varlevel, var->varnoold, var->varoattno); + + return (i); +} + +static Param* +_replace_var (Var *var) +{ + List **rt = (List**) nth (var->varlevelsup, PlannerVarParam); + List *vpe = rt[var->varno - 1]; + Param *retval; + int i; + + if ( vpe == NULL ) + { + vpe = rt[var->varno - 1] = makeNode(List); + lfirsti(vpe) = -1; + lnext(vpe) = NULL; + } + + for (i = 1; ; i++) + { + if ( i == var->varattno ) + break; + if ( lnext(vpe) == NULL ) + { + lnext(vpe) = makeNode(List); + vpe = lnext(vpe); + lfirsti(vpe) = -1; + lnext(vpe) = NULL; + } + else + vpe = lnext(vpe); + } + + if ( (i = lfirsti(vpe)) < 0 ) /* parameter is not assigned */ + { + i = _new_param (var, PlannerQueryLevel - var->varlevelsup); + } + + retval = makeNode(Param); + retval->paramkind = PARAM_EXEC; + retval->paramid = (AttrNumber) i; + retval->paramtype = var->vartype; + + return (retval); +} + +static Node* +_make_subplan (SubLink *slink) +{ + SubPlan *node = makeNode (SubPlan); + Plan *plan; + List *lst; + Node *result; + List *saved_ip = PlannerInitPlan; + + PlannerInitPlan = NULL; + + PlannerQueryLevel++; /* we becomes child */ + + node->plan = plan = union_planner ((Query*) slink->subselect); + + /* + * Assign subPlan, extParam and locParam to plan nodes. + * At the moment, SS_finalize_plan doesn't handle initPlan-s + * and so we assigne them to the topmost plan node and take + * care about its extParam too. + */ + (void) SS_finalize_plan (plan); + plan->initPlan = PlannerInitPlan; + + /* Get extParam from InitPlan-s */ + foreach (lst, PlannerInitPlan) + { + List *lp; + + foreach (lp, ((SubPlan*) lfirst (lst))->plan->extParam) + { + if ( !intMember (lfirsti(lp), plan->extParam) ) + plan->extParam = lappendi (plan->extParam, lfirsti(lp)); + } + } + + /* and now we are parent again */ + PlannerInitPlan = saved_ip; + PlannerQueryLevel--; + + node->plan_id = PlannerPlanId++; + node->rtable = ((Query*) slink->subselect)->rtable; + node->sublink = slink; + slink->subselect = NULL; /* cool ?! */ + + /* make parParam list */ + foreach (lst, plan->extParam) + { + Var *var = nth (lfirsti(lst), PlannerParamVar); + + if ( var->varlevelsup == PlannerQueryLevel ) + node->parParam = lappendi (node->parParam, lfirsti(lst)); + } + + /* + * Un-correlated or undirect correlated plans of EXISTS or EXPR + * types can be used as initPlans... + */ + if ( node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK ) + { + int i = 0; + + /* transform right side of all sublink Oper-s into Param */ + foreach (lst, slink->oper) + { + List *rside = lnext(((Expr*) lfirst(lst))->args); + TargetEntry *te = nth (i, plan->targetlist); + Var *var = makeVar (0, 0, te->resdom->restype, + te->resdom->restypmod, + PlannerQueryLevel, 0, 0); + Param *prm = makeNode(Param); + + prm->paramkind = PARAM_EXEC; + prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel); + prm->paramtype = var->vartype; + lfirst(rside) = prm; + node->setParam = lappendi (node->setParam, prm->paramid); + pfree (var); + i++; + } + PlannerInitPlan = lappend (PlannerInitPlan, node); + if ( i > 1 ) + result = (Node*) ((slink->useor) ? make_orclause (slink->oper) : + make_andclause (slink->oper)); + else + result = (Node*) lfirst (slink->oper); + } + else if ( node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK ) + { + Var *var = makeVar (0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0); + Param *prm = makeNode(Param); + + prm->paramkind = PARAM_EXEC; + prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel); + prm->paramtype = var->vartype; + node->setParam = lappendi (node->setParam, prm->paramid); + pfree (var); + PlannerInitPlan = lappend (PlannerInitPlan, node); + result = (Node*) prm; + } + else /* make expression of SUBPLAN type */ + { + Expr *expr = makeNode (Expr); + List *args = NULL; + int i = 0; + + expr->typeOid = BOOLOID; + expr->opType = SUBPLAN_EXPR; + expr->oper = (Node*) node; + + /* + * Make expr->args from parParam. Left sides of sublink Oper-s + * are handled by optimizer directly... + * Also, transform right side of sublink Oper-s into Const. + */ + foreach (lst, node->parParam) + { + Var *var = nth (lfirsti (lst), PlannerParamVar); + + var = (Var*) copyObject (var); + var->varlevelsup = 0; + args = lappend (args, var); + } + foreach (lst, slink->oper) + { + List *rside = lnext(((Expr*) lfirst(lst))->args); + TargetEntry *te = nth (i, plan->targetlist); + Const *con = makeConst (te->resdom->restype, + 0, 0, true, 0, 0, 0); + lfirst(rside) = con; + i++; + } + expr->args = args; + result = (Node*) expr; + } + + return (result); + +} + +static List * +set_unioni (List *l1, List *l2) +{ + if (l1 == NULL) + return (l2); + if (l2 == NULL) + return (l1); + + return (nconc (l1, set_differencei (l2, l1))); +} + +static List * +_finalize_primnode (void *expr, List **subplan) +{ + List *result = NULL; + + if ( expr == NULL ) + return (NULL); + + if (IsA (expr, Param)) + { + if ( ((Param*) expr)->paramkind == PARAM_EXEC ) + return (lconsi (((Param*) expr)->paramid, (List*) NULL)); + } + else if (single_node(expr)) + return (NULL); + else if (IsA (expr, List)) + { + List *le; + foreach (le, (List*) expr) + result = set_unioni (result, + _finalize_primnode (lfirst(le), subplan)); + } + else if (IsA (expr, Iter)) + return (_finalize_primnode (((Iter*) expr)->iterexpr, subplan)); + else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) || + not_clause (expr) || is_funcclause(expr)) + return (_finalize_primnode (((Expr*) expr)->args, subplan)); + else if (IsA (expr, Aggreg)) + return (_finalize_primnode (((Aggreg *) expr)->target, subplan)); + else if (IsA (expr, ArrayRef)) + { + result = _finalize_primnode (((ArrayRef*) expr)->refupperindexpr, subplan); + result = set_unioni (result, + _finalize_primnode (((ArrayRef *) expr)->reflowerindexpr, subplan)); + result = set_unioni (result, + _finalize_primnode (((ArrayRef *) expr)->refexpr, subplan)); + result = set_unioni (result, + _finalize_primnode (((ArrayRef *) expr)->refassgnexpr, subplan)); + } + else if (IsA (expr, TargetEntry)) + return (_finalize_primnode (((TargetEntry*) expr)->expr, subplan)); + else if (is_subplan (expr)) + { + List *lst; + + *subplan = lappend (*subplan, ((Expr*) expr)->oper); + foreach (lst, ((SubPlan*) ((Expr*) expr)->oper)->plan->extParam) + { + Var *var = nth (lfirsti(lst), PlannerParamVar); + + if ( var->varlevelsup < PlannerQueryLevel && + !intMember (lfirsti(lst), result) ) + result = lappendi (result, lfirsti(lst)); + } + } + else + elog (ERROR, "_finalize_primnode: can't handle node %d", + nodeTag (expr)); + + return (result); +} + +Node * +SS_replace_correlation_vars (Node *expr) +{ + + if ( expr == NULL ) + return (NULL); + if (IsA (expr, List)) + { + List *le; + foreach (le, (List*) expr) + lfirst(le) = SS_replace_correlation_vars ((Node*) lfirst(le)); + } + else if (IsA (expr, Var)) + { + if ( ((Var*) expr)->varlevelsup > 0 ) + { + Assert (((Var*) expr)->varlevelsup < PlannerQueryLevel); + expr = (Node*) _replace_var ((Var*) expr); + } + } + else if (IsA (expr, Iter)) + { + ((Iter*) expr)->iterexpr = + SS_replace_correlation_vars(((Iter*) expr)->iterexpr); + } + else if (single_node(expr)) + return (expr); + else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) || + not_clause (expr) || is_funcclause(expr)) + ((Expr *) expr)->args = (List*) + SS_replace_correlation_vars ((Node*) ((Expr *) expr)->args); + else if (IsA (expr, Aggreg)) + ((Aggreg *) expr)->target = + SS_replace_correlation_vars ((Node*) ((Aggreg *) expr)->target); + else if (IsA (expr, ArrayRef)) + { + ((ArrayRef *) expr)->refupperindexpr = (List*) + SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refupperindexpr); + ((ArrayRef *) expr)->reflowerindexpr = (List*) + SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->reflowerindexpr); + ((ArrayRef *) expr)->refexpr = + SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refexpr); + ((ArrayRef *) expr)->refassgnexpr = + SS_replace_correlation_vars (((ArrayRef *) expr)->refassgnexpr); + } + else if (IsA (expr, TargetEntry)) + ((TargetEntry*) expr)->expr = + SS_replace_correlation_vars ((Node*) ((TargetEntry*) expr)->expr); + else if (IsA (expr, SubLink)) + { + List *le; + + foreach (le, ((SubLink*) expr)->oper) /* left sides only */ + { + List *oparg = ((Expr*) lfirst (le))->args; + + lfirst (oparg) = (List*) + SS_replace_correlation_vars ((Node*) lfirst (oparg)); + } + ((SubLink*) expr)->lefthand = (List*) + SS_replace_correlation_vars ((Node*) ((SubLink*) expr)->lefthand); + } + else + elog (NOTICE, "SS_replace_correlation_vars: can't handle node %d", + nodeTag (expr)); + + return (expr); +} + +Node* +SS_process_sublinks (Node *expr) +{ + if ( expr == NULL ) + return (NULL); + if (IsA (expr, List)) + { + List *le; + foreach (le, (List*) expr) + lfirst(le) = SS_process_sublinks ((Node*) lfirst(le)); + } + else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) || + not_clause (expr) || is_funcclause(expr)) + ((Expr *) expr)->args = (List*) + SS_process_sublinks ((Node*) ((Expr *) expr)->args); + else if (IsA (expr, SubLink)) /* got it! */ + expr = _make_subplan ((SubLink*) expr); + + return (expr); +} + +List* +SS_finalize_plan (Plan *plan) +{ + List *extParam = NULL; + List *locParam = NULL; + List *subPlan = NULL; + List *param_list; + List *lst; + + if ( plan == NULL ) + return (NULL); + + param_list = _finalize_primnode (plan->targetlist, &subPlan); + Assert (subPlan == NULL); + + switch (nodeTag(plan)) + { + case T_Result: + param_list = set_unioni (param_list, + _finalize_primnode (((Result*) plan)->resconstantqual, &subPlan)); + break; + + case T_Append: + foreach (lst, ((Append*) plan)->unionplans) + param_list = set_unioni (param_list, + SS_finalize_plan ((Plan*) lfirst (lst))); + break; + + case T_IndexScan: + param_list = set_unioni (param_list, + _finalize_primnode (((IndexScan*) plan)->indxqual, &subPlan)); + Assert (subPlan == NULL); + break; + + case T_MergeJoin: + param_list = set_unioni (param_list, + _finalize_primnode (((MergeJoin*) plan)->mergeclauses, &subPlan)); + Assert (subPlan == NULL); + break; + + case T_HashJoin: + param_list = set_unioni (param_list, + _finalize_primnode (((HashJoin*) plan)->hashclauses, &subPlan)); + Assert (subPlan == NULL); + break; + + case T_Hash: + param_list = set_unioni (param_list, + _finalize_primnode (((Hash*) plan)->hashkey, &subPlan)); + Assert (subPlan == NULL); + break; + + case T_Agg: + param_list = set_unioni (param_list, + _finalize_primnode (((Agg*) plan)->aggs, &subPlan)); + Assert (subPlan == NULL); + break; + + case T_SeqScan: + case T_NestLoop: + case T_Material: + case T_Sort: + case T_Unique: + case T_Group: + break; + default: + elog(ERROR, "SS_finalize_plan: node %d unsupported", nodeTag(plan)); + return (NULL); + } + + param_list = set_unioni (param_list, _finalize_primnode (plan->qual, &subPlan)); + param_list = set_unioni (param_list, SS_finalize_plan (plan->lefttree)); + param_list = set_unioni (param_list, SS_finalize_plan (plan->righttree)); + + foreach (lst, param_list) + { + Var *var = nth (lfirsti(lst), PlannerParamVar); + + if ( var->varlevelsup < PlannerQueryLevel ) + extParam = lappendi (extParam, lfirsti(lst)); + else if ( var->varlevelsup > PlannerQueryLevel ) + elog (ERROR, "SS_finalize_plan: plan shouldn't reference subplan' variable"); + else + { + Assert (var->varno == 0 && var->varattno == 0); + locParam = lappendi (locParam, lfirsti(lst)); + } + } + + plan->extParam = extParam; + plan->locParam = locParam; + plan->subPlan = subPlan; + + return (param_list); + +} + +List *SS_pull_subplan (void *expr); + +List * +SS_pull_subplan (void *expr) +{ + List *result = NULL; + + if ( expr == NULL || single_node(expr) ) + return (NULL); + + if (IsA (expr, List)) + { + List *le; + foreach (le, (List*) expr) + result = nconc (result, SS_pull_subplan (lfirst(le))); + } + else if (IsA (expr, Iter)) + return (SS_pull_subplan (((Iter*) expr)->iterexpr)); + else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) || + not_clause (expr) || is_funcclause(expr)) + return (SS_pull_subplan (((Expr*) expr)->args)); + else if (IsA (expr, Aggreg)) + return (SS_pull_subplan (((Aggreg *) expr)->target)); + else if (IsA (expr, ArrayRef)) + { + result = SS_pull_subplan (((ArrayRef*) expr)->refupperindexpr); + result = nconc (result, + SS_pull_subplan (((ArrayRef *) expr)->reflowerindexpr)); + result = nconc (result, + SS_pull_subplan (((ArrayRef *) expr)->refexpr)); + result = nconc (result, + SS_pull_subplan (((ArrayRef *) expr)->refassgnexpr)); + } + else if (IsA (expr, TargetEntry)) + return (SS_pull_subplan (((TargetEntry*) expr)->expr)); + else if (is_subplan (expr)) + return (lcons (((Expr*) expr)->oper, NULL)); + else + elog (ERROR, "SS_pull_subplan: can't handle node %d", + nodeTag (expr)); + + return (result); +} |