aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/subselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r--src/backend/optimizer/plan/subselect.c227
1 files changed, 121 insertions, 106 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index fe17b8ebb01..840ba975a34 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.60 2002/12/12 15:49:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.61 2002/12/14 00:17:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,8 +53,17 @@ int PlannerPlanId = 0; /* to assign unique ID to subquery plans */
*/
-static void convert_sublink_opers(SubLink *slink, List *targetlist,
- List **setParams);
+typedef struct finalize_primnode_results
+{
+ List *paramids; /* List of PARAM_EXEC paramids found */
+} finalize_primnode_results;
+
+
+static List *convert_sublink_opers(List *operlist, List *lefthand,
+ List *targetlist, List **setParams);
+static Node *replace_correlation_vars_mutator(Node *node, void *context);
+static Node *process_sublinks_mutator(Node *node, void *context);
+static bool finalize_primnode(Node *node, finalize_primnode_results *results);
/*
@@ -144,30 +153,28 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
}
/*
- * Convert a bare SubLink (as created by the parser) into a SubPlanExpr.
+ * Convert a bare SubLink (as created by the parser) into a SubPlan.
+ *
+ * We are given the raw SubLink and the already-processed lefthand argument
+ * list (use this instead of the SubLink's own field).
+ *
+ * The result is whatever we need to substitute in place of the SubLink
+ * node in the executable expression. This will be either the SubPlan
+ * node (if we have to do the subplan as a subplan), or a Param node
+ * representing the result of an InitPlan, or possibly an AND or OR tree
+ * containing InitPlan Param nodes.
*/
static Node *
-make_subplan(SubLink *slink)
+make_subplan(SubLink *slink, List *lefthand)
{
- SubPlanExpr *node = makeNode(SubPlanExpr);
+ SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect);
- Oid result_type = exprType((Node *) slink);
double tuple_fraction;
Plan *plan;
List *lst;
Node *result;
/*
- * Check to see if this node was already processed; if so we have
- * trouble. We check to see if the linked-to Query appears to have
- * been planned already, too.
- */
- if (subquery == NULL)
- elog(ERROR, "make_subplan: invalid expression structure (SubLink already processed?)");
- if (subquery->base_rel_list != NIL)
- elog(ERROR, "make_subplan: invalid expression structure (subquery already processed?)");
-
- /*
* Copy the source Query node. This is a quick and dirty kluge to
* resolve the fact that the parser can generate trees with multiple
* links to the same sub-Query node, but the planner wants to scribble
@@ -210,14 +217,19 @@ make_subplan(SubLink *slink)
node->plan = plan = subquery_planner(subquery, tuple_fraction);
node->plan_id = PlannerPlanId++; /* Assign unique ID to this
- * SubPlanExpr */
+ * SubPlan */
node->rtable = subquery->rtable;
- node->sublink = slink;
-
- node->typeOid = result_type;
- slink->subselect = NULL; /* cool ?! see error check above! */
+ /*
+ * Fill in other fields of the SubPlan node.
+ */
+ node->subLinkType = slink->subLinkType;
+ node->useor = slink->useor;
+ node->oper = NIL;
+ node->setParam = NIL;
+ node->parParam = NIL;
+ node->args = NIL;
/*
* Make parParam list of params that current query level will pass to
@@ -262,17 +274,23 @@ make_subplan(SubLink *slink)
}
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
{
- convert_sublink_opers(slink, plan->targetlist, &node->setParam);
+ List *oper;
+
+ /* Convert the oper list, but don't put it into the SubPlan node */
+ oper = convert_sublink_opers(slink->oper,
+ lefthand,
+ plan->targetlist,
+ &node->setParam);
PlannerInitPlan = lappend(PlannerInitPlan, node);
- if (length(slink->oper) > 1)
- result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
- make_andclause(slink->oper));
+ if (length(oper) > 1)
+ result = (Node *) (node->useor ? make_orclause(oper) :
+ make_andclause(oper));
else
- result = (Node *) lfirst(slink->oper);
+ result = (Node *) lfirst(oper);
}
else
{
- List *args = NIL;
+ List *args;
/*
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
@@ -347,12 +365,16 @@ make_subplan(SubLink *slink)
}
}
- /* Fix the SubLink's oper list */
- convert_sublink_opers(slink, plan->targetlist, NULL);
+ /* Convert the SubLink's oper list into executable form */
+ node->oper = convert_sublink_opers(slink->oper,
+ lefthand,
+ plan->targetlist,
+ NULL);
/*
* Make node->args from parParam.
*/
+ args = NIL;
foreach(lst, node->parParam)
{
Var *var = nth(lfirsti(lst), PlannerParamVar);
@@ -379,27 +401,26 @@ make_subplan(SubLink *slink)
* convert_sublink_opers: convert a SubLink's oper list from the
* parser/rewriter format into the executor's format.
*
- * The oper list is initially just a list of OpExpr nodes. We replace it
- * with a list of actually executable expressions, in which the specified
- * operators are applied to corresponding elements of the lefthand list
- * and Params representing the results of the subplan. lefthand is then
- * set to NIL.
+ * The oper list is initially a list of OpExpr nodes with NIL args. We
+ * convert it to a list of actually executable expressions, in which the
+ * specified operators are applied to corresponding elements of the
+ * lefthand list and Params representing the results of the subplan.
*
* If setParams is not NULL, the paramids of the Params created are added
* to the *setParams list.
*/
-static void
-convert_sublink_opers(SubLink *slink, List *targetlist,
- List **setParams)
+static List *
+convert_sublink_opers(List *operlist, List *lefthand,
+ List *targetlist, List **setParams)
{
List *newoper = NIL;
- List *leftlist = slink->lefthand;
+ List *leftlist = lefthand;
List *lst;
- foreach(lst, slink->oper)
+ foreach(lst, operlist)
{
OpExpr *oper = (OpExpr *) lfirst(lst);
- Node *lefthand = lfirst(leftlist);
+ Node *leftop = lfirst(leftlist);
TargetEntry *te = lfirst(targetlist);
Param *prm;
Operator tup;
@@ -430,7 +451,7 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
- left = make_operand(lefthand, exprType(lefthand), opform->oprleft);
+ left = make_operand(leftop, exprType(leftop), opform->oprleft);
right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
newoper = lappend(newoper,
make_opclause(oper->opno,
@@ -445,65 +466,12 @@ convert_sublink_opers(SubLink *slink, List *targetlist,
targetlist = lnext(targetlist);
}
- slink->oper = newoper;
- slink->lefthand = NIL;
-}
-
-/*
- * finalize_primnode: build lists of params appearing
- * in the given expression tree. NOTE: items are added to list passed in,
- * so caller must initialize list to NIL before first call!
- */
-
-typedef struct finalize_primnode_results
-{
- List *paramids; /* List of PARAM_EXEC paramids found */
-} finalize_primnode_results;
-
-static bool
-finalize_primnode(Node *node, finalize_primnode_results *results)
-{
- if (node == NULL)
- return false;
- if (IsA(node, Param))
- {
- if (((Param *) node)->paramkind == PARAM_EXEC)
- {
- int paramid = (int) ((Param *) node)->paramid;
-
- if (!intMember(paramid, results->paramids))
- results->paramids = lconsi(paramid, results->paramids);
- }
- return false; /* no more to do here */
- }
- if (is_subplan(node))
- {
- SubPlanExpr *subplan = (SubPlanExpr *) node;
- List *lst;
-
- /* Check extParam list for params to add to paramids */
- foreach(lst, subplan->plan->extParam)
- {
- int paramid = lfirsti(lst);
- Var *var = nth(paramid, PlannerParamVar);
-
- /* note varlevelsup is absolute level number */
- if (var->varlevelsup < PlannerQueryLevel &&
- !intMember(paramid, results->paramids))
- results->paramids = lconsi(paramid, results->paramids);
- }
- /* fall through to recurse into subplan args */
- }
- return expression_tree_walker(node, finalize_primnode,
- (void *) results);
+ return newoper;
}
/*
* Replace correlation vars (uplevel vars) with Params.
*/
-
-static Node *replace_correlation_vars_mutator(Node *node, void *context);
-
Node *
SS_replace_correlation_vars(Node *expr)
{
@@ -529,9 +497,6 @@ replace_correlation_vars_mutator(Node *node, void *context)
/*
* Expand SubLinks to SubPlans in the given expression.
*/
-
-static Node *process_sublinks_mutator(Node *node, void *context);
-
Node *
SS_process_sublinks(Node *expr)
{
@@ -547,20 +512,21 @@ process_sublinks_mutator(Node *node, void *context)
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
+ List *lefthand;
/*
- * First, scan the lefthand-side expressions, if any. This is a
- * tad klugy since we modify the input SubLink node, but that
- * should be OK (make_subplan does it too!)
+ * First, recursively process the lefthand-side expressions, if any.
*/
- sublink->lefthand = (List *)
+ lefthand = (List *)
process_sublinks_mutator((Node *) sublink->lefthand, context);
- /* Now build the SubPlanExpr node and make the expr to return */
- return make_subplan(sublink);
+ /*
+ * Now build the SubPlan node and make the expr to return.
+ */
+ return make_subplan(sublink, lefthand);
}
/*
- * Note that we will never see a SubPlanExpr expression in the input
+ * Note that we will never see a SubPlan expression in the input
* (since this is the very routine that creates 'em to begin with). So
* the code in expression_tree_mutator() that might do inappropriate
* things with SubPlans or SubLinks will not be exercised.
@@ -572,6 +538,12 @@ process_sublinks_mutator(Node *node, void *context)
context);
}
+/*
+ * SS_finalize_plan - do final sublink processing for a completed Plan.
+ *
+ * This recursively computes and sets the extParam and locParam lists
+ * for every Plan node in the given tree.
+ */
List *
SS_finalize_plan(Plan *plan, List *rtable)
{
@@ -721,3 +693,46 @@ SS_finalize_plan(Plan *plan, List *rtable)
return results.paramids;
}
+
+/*
+ * finalize_primnode: build lists of params appearing
+ * in the given expression tree. NOTE: items are added to list passed in,
+ * so caller must initialize list to NIL before first call!
+ */
+static bool
+finalize_primnode(Node *node, finalize_primnode_results *results)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Param))
+ {
+ if (((Param *) node)->paramkind == PARAM_EXEC)
+ {
+ int paramid = (int) ((Param *) node)->paramid;
+
+ if (!intMember(paramid, results->paramids))
+ results->paramids = lconsi(paramid, results->paramids);
+ }
+ return false; /* no more to do here */
+ }
+ if (is_subplan(node))
+ {
+ SubPlan *subplan = (SubPlan *) node;
+ List *lst;
+
+ /* Check extParam list for params to add to paramids */
+ foreach(lst, subplan->plan->extParam)
+ {
+ int paramid = lfirsti(lst);
+ Var *var = nth(paramid, PlannerParamVar);
+
+ /* note varlevelsup is absolute level number */
+ if (var->varlevelsup < PlannerQueryLevel &&
+ !intMember(paramid, results->paramids))
+ results->paramids = lconsi(paramid, results->paramids);
+ }
+ /* fall through to recurse into subplan args */
+ }
+ return expression_tree_walker(node, finalize_primnode,
+ (void *) results);
+}