aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/plan/Makefile4
-rw-r--r--src/backend/optimizer/plan/createplan.c4
-rw-r--r--src/backend/optimizer/plan/planmain.c19
-rw-r--r--src/backend/optimizer/plan/planner.c53
-rw-r--r--src/backend/optimizer/plan/setrefs.c16
-rw-r--r--src/backend/optimizer/plan/subselect.c549
6 files changed, 625 insertions, 20 deletions
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);
+}