From 4a6e3a6a9fa18e01d6ae65015e55a42f36030d0d Mon Sep 17 00:00:00 2001 From: "Vadim B. Mikheev" <vadim4o@yahoo.com> Date: Fri, 13 Feb 1998 03:37:04 +0000 Subject: [PATCH] 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. --- src/backend/optimizer/plan/Makefile | 4 +- src/backend/optimizer/plan/createplan.c | 4 +- src/backend/optimizer/plan/planmain.c | 19 +- src/backend/optimizer/plan/planner.c | 53 ++- src/backend/optimizer/plan/setrefs.c | 16 +- src/backend/optimizer/plan/subselect.c | 549 ++++++++++++++++++++++++ 6 files changed, 625 insertions(+), 20 deletions(-) create mode 100644 src/backend/optimizer/plan/subselect.c diff --git a/src/backend/optimizer/plan/Makefile b/src/backend/optimizer/plan/Makefile index b6a9ba0816b..19690ae2081 100644 --- a/src/backend/optimizer/plan/Makefile +++ b/src/backend/optimizer/plan/Makefile @@ -4,7 +4,7 @@ # Makefile for optimizer/plan # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/optimizer/plan/Makefile,v 1.5 1997/12/20 00:24:31 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/optimizer/plan/Makefile,v 1.6 1998/02/13 03:36:51 vadim Exp $ # #------------------------------------------------------------------------- @@ -15,7 +15,7 @@ INCLUDE_OPT = -I../.. CFLAGS+=$(INCLUDE_OPT) -OBJS = createplan.o initsplan.o planmain.o planner.o setrefs.o +OBJS = createplan.o initsplan.o planmain.o planner.o setrefs.o subselect.o # not ready yet: predmig.o xfunc.o diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index f6a1470be8e..85ede31987e 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.25 1998/02/10 04:01:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.26 1998/02/13 03:36:54 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -685,13 +685,11 @@ fix_indxqual_references(Node *clause, Path *index_path) else if (IsA(clause, Const)) { return (clause); -#ifdef INDEXSCAN_PATCH } else if (IsA(clause, Param)) { /* Function parameter used as index scan arg. DZ - 27-8-1996 */ return (clause); -#endif } else if (is_opclause(clause) && is_funcclause((Node *) get_leftop((Expr *) clause)) && diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 10e67b76cd2..ca5859cb04b 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.18 1998/02/10 04:01:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.19 1998/02/13 03:36:57 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -22,7 +22,9 @@ #include "nodes/makefuncs.h" #include "optimizer/planmain.h" +#include "optimizer/subselect.h" #include "optimizer/internal.h" +#include "optimizer/prep.h" #include "optimizer/paths.h" #include "optimizer/clauses.h" #include "optimizer/keys.h" @@ -72,7 +74,18 @@ query_planner(Query *root, List *var_only_tlist = NIL; List *level_tlist = NIL; Plan *subplan = NULL; - + + if ( PlannerQueryLevel > 1 ) + { + /* should copy be made ? */ + tlist = (List *) SS_replace_correlation_vars ((Node*)tlist); + qual = (List *) SS_replace_correlation_vars ((Node*)qual); + } + if (root->hasSubLinks) + qual = (List *) SS_process_sublinks ((Node*) qual); + + qual = cnfify((Expr *) qual, true); + /* * A command without a target list or qualification is an error, * except for "delete foo". @@ -145,7 +158,7 @@ query_planner(Query *root, if (constant_qual != NULL) { return ((Plan *) make_result(tlist, - (Node *) constant_qual, + (Node *) constant_qual, (Plan *) scan)); } else diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5643b675f96..367978eb57b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7,11 +7,12 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.21 1998/01/15 18:59:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.22 1998/02/13 03:36:59 vadim Exp $ * *------------------------------------------------------------------------- */ #include <sys/types.h> +#include <string.h> #include "postgres.h" @@ -30,6 +31,7 @@ #include "optimizer/plancat.h" #include "optimizer/prep.h" #include "optimizer/planmain.h" +#include "optimizer/subselect.h" #include "optimizer/paths.h" #include "optimizer/cost.h" @@ -56,10 +58,32 @@ extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup, * *****************************************************************************/ +Plan* +planner(Query *parse) +{ + Plan *result_plan; + + PlannerQueryLevel = 1; + PlannerVarParam = NULL; + PlannerParamVar = NULL; + PlannerInitPlan = NULL; + PlannerPlanId = 0; + + result_plan = union_planner (parse); + + Assert (PlannerQueryLevel == 1); + if ( PlannerPlanId > 0 ) + { + result_plan->initPlan = PlannerInitPlan; + (void) SS_finalize_plan (result_plan); + } + result_plan->nParamExec = length (PlannerParamVar); + + return (result_plan); +} /* - * planner-- - * Main query optimizer routine. + * union_planner-- * * Invokes the planner on union queries if there are any left, * recursing if necessary to get them all, then processes normal plans. @@ -68,14 +92,13 @@ extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup, * */ Plan * -planner(Query *parse) +union_planner(Query *parse) { List *tlist = parse->targetList; List *rangetable = parse->rtable; Plan *result_plan = (Plan *) NULL; - List *primary_qual; Index rt_index; @@ -100,17 +123,25 @@ planner(Query *parse) } else { + List **vpm = NULL; + tlist = preprocess_targetlist(tlist, parse->commandType, parse->resultRelation, parse->rtable); - - primary_qual = cnfify((Expr *) parse->qual, true); - + if ( parse->rtable != NULL ) + { + vpm = (List **) palloc (length (parse->rtable) * sizeof (List*)); + memset (vpm, 0, length (parse->rtable) * sizeof (List*)); + } + PlannerVarParam = lcons (vpm, PlannerVarParam); result_plan = query_planner(parse, - parse->commandType, - tlist, - primary_qual); + parse->commandType, + tlist, + (List*) parse->qual); + PlannerVarParam = lnext (PlannerVarParam); + if ( vpm != NULL ) + pfree (vpm); } /* diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 16fd96aae1b..fc51657b8d0 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.17 1998/02/10 04:01:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.18 1998/02/13 03:37:02 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -405,7 +405,21 @@ replace_clause_joinvar_refs(Expr *clause, leftvar, rightvar)); } + else if (is_subplan(clause)) + { + ((Expr*) clause)->args = + replace_subclause_joinvar_refs(((Expr*) clause)->args, + outer_tlist, + inner_tlist); + ((SubPlan*) ((Expr*) clause)->oper)->sublink->oper = + replace_subclause_joinvar_refs(((SubPlan*) ((Expr*) clause)->oper)->sublink->oper, + outer_tlist, + inner_tlist); + return ((List*) clause); + } /* shouldn't reach here */ + elog (ERROR, "replace_clause_joinvar_refs: unsupported clause %d", + nodeTag (clause)); return NULL; } 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); +} -- GitLab