aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/copyfuncs.c37
-rw-r--r--src/backend/optimizer/plan/createplan.c22
-rw-r--r--src/backend/optimizer/plan/setrefs.c83
-rw-r--r--src/backend/optimizer/plan/subselect.c41
-rw-r--r--src/backend/optimizer/util/clauses.c136
-rw-r--r--src/include/optimizer/clauses.h8
-rw-r--r--src/include/optimizer/subselect.h1
7 files changed, 194 insertions, 134 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 836687240d5..41918cda142 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -8,15 +8,15 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.110 2000/03/22 22:08:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.111 2000/04/04 01:21:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
-#include "optimizer/subselect.h"
/*
@@ -88,9 +88,10 @@ CopyPlanFields(Plan *from, Plan *newnode)
newnode->locParam = listCopy(from->locParam);
newnode->chgParam = listCopy(from->chgParam);
Node_Copy(from, newnode, initPlan);
+ /* subPlan list must point to subplans in the new subtree, not the old */
if (from->subPlan != NIL)
- newnode->subPlan = nconc(SS_pull_subplan((Node *) newnode->targetlist),
- SS_pull_subplan((Node *) newnode->qual));
+ newnode->subPlan = nconc(pull_subplans((Node *) newnode->targetlist),
+ pull_subplans((Node *) newnode->qual));
else
newnode->subPlan = NIL;
newnode->nParamExec = from->nParamExec;
@@ -142,7 +143,7 @@ _copyResult(Result *from)
*/
if (from->plan.subPlan != NIL)
newnode->plan.subPlan = nconc(newnode->plan.subPlan,
- SS_pull_subplan(newnode->resconstantqual));
+ pull_subplans(newnode->resconstantqual));
return newnode;
}
@@ -252,6 +253,17 @@ _copyIndexScan(IndexScan *from)
Node_Copy(from, newnode, indxqualorig);
newnode->indxorderdir = from->indxorderdir;
+ /*
+ * We must add subplans in index quals to the new plan's subPlan list
+ */
+ if (from->scan.plan.subPlan != NIL)
+ {
+ newnode->scan.plan.subPlan = nconc(newnode->scan.plan.subPlan,
+ pull_subplans((Node *) newnode->indxqual));
+ newnode->scan.plan.subPlan = nconc(newnode->scan.plan.subPlan,
+ pull_subplans((Node *) newnode->indxqualorig));
+ }
+
return newnode;
}
@@ -358,6 +370,13 @@ _copyMergeJoin(MergeJoin *from)
*/
Node_Copy(from, newnode, mergeclauses);
+ /*
+ * We must add subplans in mergeclauses to the new plan's subPlan list
+ */
+ if (from->join.subPlan != NIL)
+ newnode->join.subPlan = nconc(newnode->join.subPlan,
+ pull_subplans((Node *) newnode->mergeclauses));
+
return newnode;
}
@@ -382,9 +401,15 @@ _copyHashJoin(HashJoin *from)
* ----------------
*/
Node_Copy(from, newnode, hashclauses);
-
newnode->hashjoinop = from->hashjoinop;
+ /*
+ * We must add subplans in hashclauses to the new plan's subPlan list
+ */
+ if (from->join.subPlan != NIL)
+ newnode->join.subPlan = nconc(newnode->join.subPlan,
+ pull_subplans((Node *) newnode->hashclauses));
+
return newnode;
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 8e20ae302e1..3fab7f08b87 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.87 2000/03/22 22:08:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.88 2000/04/04 01:21:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -724,7 +724,9 @@ create_hashjoin_node(HashPath *best_path,
* track of which index applies to each subgroup of index qual clauses...
*
* Returns a modified copy of the indexqual list --- the original is not
- * changed.
+ * changed. Note also that the copy shares no substructure with the
+ * original; this is needed in case there is a subplan in it (we need
+ * two separate copies of the subplan tree, or things will go awry).
*/
static List *
@@ -808,11 +810,13 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
get_relattval((Node *) clause, baserelid,
&relid, &attno, &constval, &flag);
- /* Copy enough structure to allow commuting and replacing an operand
- * without changing original clause.
+ /* Make a copy that will become the fixed clause.
+ *
+ * We used to try to do a shallow copy here, but that fails if there
+ * is a subplan in the arguments of the opclause. So just do a
+ * full copy.
*/
- newclause = make_clause(clause->opType, clause->oper,
- listCopy(clause->args));
+ newclause = (Expr *) copyObject((Node *) clause);
/* If the indexkey is on the right, commute the clause. */
if ((flag & SEL_RIGHT) == 0)
@@ -834,11 +838,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
newopno = indexable_operator(newclause, opclass, relam, true);
if (newopno == InvalidOid)
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
- if (newopno != ((Oper *) newclause->oper)->opno)
- {
- newclause->oper = (Node *) copyObject(newclause->oper);
- ((Oper *) newclause->oper)->opno = newopno;
- }
+ ((Oper *) newclause->oper)->opno = newopno;
fixed_qual = lappend(fixed_qual, newclause);
}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index b44aa6408b8..756333e0059 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.60 2000/01/26 05:56:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.61 2000/04/04 01:21:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,6 +59,8 @@ static bool fix_opids_walker(Node *node, void *context);
* for the convenience of the executor. We update Vars in upper plan nodes
* to refer to the outputs of their subplans, and we compute regproc OIDs
* for operators (ie, we look up the function that implements each op).
+ * We must also build lists of all the subplan nodes present in each
+ * plan node's expression trees.
*
* set_plan_references recursively traverses the whole plan tree.
*
@@ -72,6 +74,11 @@ set_plan_references(Plan *plan)
if (plan == NULL)
return;
+ /* We must rebuild the plan's list of subplan nodes, since we are
+ * copying/mutating its expression trees.
+ */
+ plan->subPlan = NIL;
+
/*
* Plan-type-specific fixes
*/
@@ -83,6 +90,12 @@ set_plan_references(Plan *plan)
case T_IndexScan:
fix_opids((Node *) ((IndexScan *) plan)->indxqual);
fix_opids((Node *) ((IndexScan *) plan)->indxqualorig);
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) ((IndexScan *) plan)->indxqual));
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) ((IndexScan *) plan)->indxqualorig));
break;
case T_NestLoop:
set_join_references((Join *) plan);
@@ -90,10 +103,16 @@ set_plan_references(Plan *plan)
case T_MergeJoin:
set_join_references((Join *) plan);
fix_opids((Node *) ((MergeJoin *) plan)->mergeclauses);
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) ((MergeJoin *) plan)->mergeclauses));
break;
case T_HashJoin:
set_join_references((Join *) plan);
fix_opids((Node *) ((HashJoin *) plan)->hashclauses);
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) ((HashJoin *) plan)->hashclauses));
break;
case T_Material:
case T_Sort:
@@ -119,6 +138,9 @@ set_plan_references(Plan *plan)
if (plan->lefttree != NULL)
set_uppernode_references(plan, (Index) OUTER);
fix_opids(((Result *) plan)->resconstantqual);
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans(((Result *) plan)->resconstantqual));
break;
case T_Append:
foreach(pl, ((Append *) plan)->appendplans)
@@ -136,10 +158,17 @@ set_plan_references(Plan *plan)
}
/*
- * For all plan types, fix operators in targetlist and qual expressions
+ * For all plan types, fix operators in targetlist and qual expressions,
+ * and find subplans therein.
*/
fix_opids((Node *) plan->targetlist);
fix_opids((Node *) plan->qual);
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) plan->targetlist));
+ plan->subPlan =
+ nconc(plan->subPlan,
+ pull_subplans((Node *) plan->qual));
/*
* Now recurse into subplans, if any
@@ -302,31 +331,7 @@ join_references_mutator(Node *node,
*/
if (var->varno != context->acceptable_rel)
elog(ERROR, "join_references: variable not in subplan target lists");
- return (Node *) newvar; /* copy is probably not necessary here... */
- }
- /*
- * expression_tree_mutator will copy SubPlan nodes if given a chance.
- * We do not want to do that here, because subselect.c has already
- * constructed the initPlan and subPlan lists of the current plan node
- * and we mustn't leave those dangling (ie, pointing to different
- * copies of the nodes than what's in the targetlist & quals...)
- * Instead, alter the SubPlan in-place. Grotty --- is there a better way?
- */
- if (is_subplan(node))
- {
- Expr *expr = (Expr *) node;
- SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
-
- /* transform args list (params to be passed to subplan) */
- expr->args = (List *)
- join_references_mutator((Node *) expr->args,
- context);
- /* transform sublink's oper list as well */
- sublink->oper = (List *)
- join_references_mutator((Node *) sublink->oper,
- context);
-
- return (Node *) expr;
+ return (Node *) newvar;
}
return expression_tree_mutator(node,
join_references_mutator,
@@ -383,30 +388,6 @@ replace_vars_with_subplan_refs_mutator(Node *node,
newvar->varattno = resdom->resno;
return (Node *) newvar;
}
- /*
- * expression_tree_mutator will copy SubPlan nodes if given a chance.
- * We do not want to do that here, because subselect.c has already
- * constructed the initPlan and subPlan lists of the current plan node
- * and we mustn't leave those dangling (ie, pointing to different
- * copies of the nodes than what's in the targetlist & quals...)
- * Instead, alter the SubPlan in-place. Grotty --- is there a better way?
- */
- if (is_subplan(node))
- {
- Expr *expr = (Expr *) node;
- SubLink *sublink = ((SubPlan *) expr->oper)->sublink;
-
- /* transform args list (params to be passed to subplan) */
- expr->args = (List *)
- replace_vars_with_subplan_refs_mutator((Node *) expr->args,
- context);
- /* transform sublink's oper list as well */
- sublink->oper = (List *)
- replace_vars_with_subplan_refs_mutator((Node *) sublink->oper,
- context);
-
- return (Node *) expr;
- }
return expression_tree_mutator(node,
replace_vars_with_subplan_refs_mutator,
(void *) context);
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 3928f578360..b77d8b586f6 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.33 2000/03/21 05:12:02 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.34 2000/04/04 01:21:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -442,6 +442,12 @@ set_unioni(List *l1, List *l2)
* finalize_primnode: build lists of subplans and params appearing
* in the given expression tree. NOTE: items are added to lists passed in,
* so caller must initialize lists to NIL before first call!
+ *
+ * Note: the subplan list that is constructed here and assigned to the
+ * plan's subPlan field will be replaced with an up-to-date list in
+ * set_plan_references(). We could almost dispense with building this
+ * subplan list at all; I believe the only place that uses it is the
+ * check in make_subplan to see whether a subselect has any subselects.
*/
typedef struct finalize_primnode_results {
@@ -604,6 +610,10 @@ SS_finalize_plan(Plan *plan)
case T_IndexScan:
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
&results);
+ /* we need not look at indxqualorig, since it will have the
+ * same param references as indxqual, and we aren't really
+ * concerned yet about having a complete subplan list.
+ */
break;
case T_MergeJoin:
@@ -670,32 +680,3 @@ SS_finalize_plan(Plan *plan)
return results.paramids;
}
-
-/*
- * Construct a list of all subplans found within the given node tree.
- */
-
-static bool SS_pull_subplan_walker(Node *node, List **listptr);
-
-List *
-SS_pull_subplan(Node *expr)
-{
- List *result = NIL;
-
- SS_pull_subplan_walker(expr, &result);
- return result;
-}
-
-static bool
-SS_pull_subplan_walker(Node *node, List **listptr)
-{
- if (node == NULL)
- return false;
- if (is_subplan(node))
- {
- *listptr = lappend(*listptr, ((Expr *) node)->oper);
- /* fall through to check args to subplan */
- }
- return expression_tree_walker(node, SS_pull_subplan_walker,
- (void *) listptr);
-}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8d4dae486ac..d429db93a03 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.63 2000/03/21 05:12:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.64 2000/04/04 01:21:46 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -43,6 +43,8 @@
static bool contain_agg_clause_walker(Node *node, void *context);
static bool pull_agg_clause_walker(Node *node, List **listptr);
+static bool contain_subplans_walker(Node *node, void *context);
+static bool pull_subplans_walker(Node *node, List **listptr);
static bool check_subplans_for_ungrouped_vars_walker(Node *node,
Query *context);
static int is_single_func(Node *node);
@@ -358,39 +360,9 @@ make_ands_implicit(Expr *clause)
/*****************************************************************************
- * *
- * General clause-manipulating routines *
- * *
+ * Aggregate-function clause manipulation
*****************************************************************************/
-
-/*
- * pull_constant_clauses
- * Scans through a list of qualifications and find those that
- * contain no variables (of the current query level).
- *
- * Returns a list of the constant clauses in constantQual and the remaining
- * quals as the return value.
- *
- */
-List *
-pull_constant_clauses(List *quals, List **constantQual)
-{
- List *q;
- List *constqual = NIL;
- List *restqual = NIL;
-
- foreach(q, quals)
- {
- if (!contain_var_clause(lfirst(q)))
- constqual = lcons(lfirst(q), constqual);
- else
- restqual = lcons(lfirst(q), restqual);
- }
- *constantQual = constqual;
- return restqual;
-}
-
/*
* contain_agg_clause
* Recursively search for Aggref nodes within a clause.
@@ -454,6 +426,68 @@ pull_agg_clause_walker(Node *node, List **listptr)
(void *) listptr);
}
+
+/*****************************************************************************
+ * Subplan clause manipulation
+ *****************************************************************************/
+
+/*
+ * contain_subplans
+ * Recursively search for subplan nodes within a clause.
+ *
+ * If we see a SubLink node, we will return TRUE. This is only possible if
+ * the expression tree hasn't yet been transformed by subselect.c. We do not
+ * know whether the node will produce a true subplan or just an initplan,
+ * but we make the conservative assumption that it will be a subplan.
+ *
+ * Returns true if any subplan found.
+ */
+bool
+contain_subplans(Node *clause)
+{
+ return contain_subplans_walker(clause, NULL);
+}
+
+static bool
+contain_subplans_walker(Node *node, void *context)
+{
+ if (node == NULL)
+ return false;
+ if (is_subplan(node) || IsA(node, SubLink))
+ return true; /* abort the tree traversal and return true */
+ return expression_tree_walker(node, contain_subplans_walker, context);
+}
+
+/*
+ * pull_subplans
+ * Recursively pulls all subplans from an expression tree.
+ *
+ * Returns list of subplan nodes found. Note the nodes themselves are not
+ * copied, only referenced.
+ */
+List *
+pull_subplans(Node *clause)
+{
+ List *result = NIL;
+
+ pull_subplans_walker(clause, &result);
+ return result;
+}
+
+static bool
+pull_subplans_walker(Node *node, List **listptr)
+{
+ if (node == NULL)
+ return false;
+ if (is_subplan(node))
+ {
+ *listptr = lappend(*listptr, ((Expr *) node)->oper);
+ /* fall through to check args to subplan */
+ }
+ return expression_tree_walker(node, pull_subplans_walker,
+ (void *) listptr);
+}
+
/*
* check_subplans_for_ungrouped_vars
* Check for subplans that are being passed ungrouped variables as
@@ -556,6 +590,41 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
}
+/*****************************************************************************
+ * *
+ * General clause-manipulating routines *
+ * *
+ *****************************************************************************/
+
+
+/*
+ * pull_constant_clauses
+ * Scans through a list of qualifications and find those that
+ * contain no variables (of the current query level).
+ *
+ * Returns a list of the constant clauses in constantQual and the remaining
+ * quals as the return value.
+ *
+ */
+List *
+pull_constant_clauses(List *quals, List **constantQual)
+{
+ List *q;
+ List *constqual = NIL;
+ List *restqual = NIL;
+
+ foreach(q, quals)
+ {
+ if (!contain_var_clause(lfirst(q)))
+ constqual = lcons(lfirst(q), constqual);
+ else
+ restqual = lcons(lfirst(q), restqual);
+ }
+ *constantQual = constqual;
+ return restqual;
+}
+
+
/*
* clause_relids_vars
* Retrieves distinct relids and vars appearing within a clause.
@@ -726,7 +795,8 @@ default_results:
* If the given expression is a function of a single relation,
* return the relation number; else return 0
*/
-static int is_single_func(Node *node)
+static int
+is_single_func(Node *node)
{
if (is_funcclause(node))
{
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index ef2bfeb63b6..a6f6ea2e5f3 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: clauses.h,v 1.34 2000/03/21 05:11:51 tgl Exp $
+ * $Id: clauses.h,v 1.35 2000/04/04 01:21:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,11 +38,15 @@ extern Expr *make_andclause(List *andclauses);
extern Expr *make_ands_explicit(List *andclauses);
extern List *make_ands_implicit(Expr *clause);
-extern List *pull_constant_clauses(List *quals, List **constantQual);
extern bool contain_agg_clause(Node *clause);
extern List *pull_agg_clause(Node *clause);
+
+extern bool contain_subplans(Node *clause);
+extern List *pull_subplans(Node *clause);
extern void check_subplans_for_ungrouped_vars(Node *clause, Query *query);
+extern List *pull_constant_clauses(List *quals, List **constantQual);
+
extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
extern int NumRelids(Node *clause);
extern void get_relattval(Node *clause, int targetrelid,
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index a00158deb94..f4e51121613 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -17,6 +17,5 @@ extern int PlannerPlanId; /* to assign unique ID to subquery plans */
extern List *SS_finalize_plan(Plan *plan);
extern Node *SS_replace_correlation_vars(Node *expr);
extern Node *SS_process_sublinks(Node *expr);
-extern List *SS_pull_subplan(Node *expr);
#endif /* SUBSELECT_H */