summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c143
1 files changed, 68 insertions, 75 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0dd9e1e8d2a..e007e4e594e 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.196 2005/12/20 02:30:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.197 2006/01/31 21:39:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,16 +47,17 @@ ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
/* Expression kind codes for preprocess_expression */
-#define EXPRKIND_QUAL 0
-#define EXPRKIND_TARGET 1
-#define EXPRKIND_RTFUNC 2
-#define EXPRKIND_LIMIT 3
-#define EXPRKIND_ININFO 4
+#define EXPRKIND_QUAL 0
+#define EXPRKIND_TARGET 1
+#define EXPRKIND_RTFUNC 2
+#define EXPRKIND_LIMIT 3
+#define EXPRKIND_ININFO 4
+#define EXPRKIND_APPINFO 5
static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
-static Plan *inheritance_planner(PlannerInfo *root, List *inheritlist);
+static Plan *inheritance_planner(PlannerInfo *root);
static Plan *grouping_planner(PlannerInfo *root, double tuple_fraction);
static double preprocess_limit(PlannerInfo *root,
double tuple_fraction,
@@ -194,7 +195,6 @@ subquery_planner(Query *parse, double tuple_fraction,
PlannerInfo *root;
Plan *plan;
List *newHaving;
- List *lst;
ListCell *l;
/* Set up for a new level of subquery */
@@ -204,6 +204,8 @@ subquery_planner(Query *parse, double tuple_fraction,
/* Create a PlannerInfo data structure for this subquery */
root = makeNode(PlannerInfo);
root->parse = parse;
+ root->in_info_list = NIL;
+ root->append_rel_list = NIL;
/*
* Look for IN clauses at the top level of WHERE, and transform them into
@@ -211,7 +213,6 @@ subquery_planner(Query *parse, double tuple_fraction,
* level of WHERE; if we pull up any subqueries in the next step, their
* INs are processed just before pulling them up.
*/
- root->in_info_list = NIL;
if (parse->hasSubLinks)
parse->jointree->quals = pull_up_IN_clauses(root,
parse->jointree->quals);
@@ -253,6 +254,16 @@ subquery_planner(Query *parse, double tuple_fraction,
}
/*
+ * Expand any rangetable entries that are inheritance sets into "append
+ * relations". This can add entries to the rangetable, but they must be
+ * plain base relations not joins, so it's OK (and marginally more
+ * efficient) to do it after checking for join RTEs. We must do it after
+ * pulling up subqueries, else we'd fail to handle inherited tables in
+ * subqueries.
+ */
+ expand_inherited_tables(root);
+
+ /*
* Set hasHavingQual to remember if HAVING clause is present. Needed
* because preprocess_expression will reduce a constant-true condition to
* an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
@@ -279,6 +290,9 @@ subquery_planner(Query *parse, double tuple_fraction,
root->in_info_list = (List *)
preprocess_expression(root, (Node *) root->in_info_list,
EXPRKIND_ININFO);
+ root->append_rel_list = (List *)
+ preprocess_expression(root, (Node *) root->append_rel_list,
+ EXPRKIND_APPINFO);
/* Also need to preprocess expressions for function RTEs */
foreach(l, parse->rtable)
@@ -357,8 +371,8 @@ subquery_planner(Query *parse, double tuple_fraction,
* needs special processing, else go straight to grouping_planner.
*/
if (parse->resultRelation &&
- (lst = expand_inherited_rtentry(root, parse->resultRelation)) != NIL)
- plan = inheritance_planner(root, lst);
+ rt_fetch(parse->resultRelation, parse->rtable)->inh)
+ plan = inheritance_planner(root);
else
plan = grouping_planner(root, tuple_fraction);
@@ -504,44 +518,50 @@ preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
(int) nodeTag(jtnode));
}
-/*--------------------
+/*
* inheritance_planner
* Generate a plan in the case where the result relation is an
* inheritance set.
*
- * We have to handle this case differently from cases where a source
- * relation is an inheritance set. Source inheritance is expanded at
- * the bottom of the plan tree (see allpaths.c), but target inheritance
- * has to be expanded at the top. The reason is that for UPDATE, each
- * target relation needs a different targetlist matching its own column
- * set. (This is not so critical for DELETE, but for simplicity we treat
- * inherited DELETE the same way.) Fortunately, the UPDATE/DELETE target
- * can never be the nullable side of an outer join, so it's OK to generate
- * the plan this way.
- *
- * inheritlist is an integer list of RT indexes for the result relation set.
+ * We have to handle this case differently from cases where a source relation
+ * is an inheritance set. Source inheritance is expanded at the bottom of the
+ * plan tree (see allpaths.c), but target inheritance has to be expanded at
+ * the top. The reason is that for UPDATE, each target relation needs a
+ * different targetlist matching its own column set. Also, for both UPDATE
+ * and DELETE, the executor needs the Append plan node at the top, else it
+ * can't keep track of which table is the current target table. Fortunately,
+ * the UPDATE/DELETE target can never be the nullable side of an outer join,
+ * so it's OK to generate the plan this way.
*
* Returns a query plan.
- *--------------------
*/
static Plan *
-inheritance_planner(PlannerInfo *root, List *inheritlist)
+inheritance_planner(PlannerInfo *root)
{
Query *parse = root->parse;
int parentRTindex = parse->resultRelation;
- Oid parentOID = getrelid(parentRTindex, parse->rtable);
- int mainrtlength = list_length(parse->rtable);
List *subplans = NIL;
List *tlist = NIL;
+ PlannerInfo subroot;
ListCell *l;
- foreach(l, inheritlist)
+ subroot.parse = NULL; /* catch it if no matches in loop */
+
+ parse->resultRelations = NIL;
+
+ foreach(l, root->append_rel_list)
{
- int childRTindex = lfirst_int(l);
- Oid childOID = getrelid(childRTindex, parse->rtable);
- PlannerInfo subroot;
+ AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
Plan *subplan;
+ /* append_rel_list contains all append rels; ignore others */
+ if (appinfo->parent_relid != parentRTindex)
+ continue;
+
+ /* Build target-relations list for the executor */
+ parse->resultRelations = lappend_int(parse->resultRelations,
+ appinfo->child_relid);
+
/*
* Generate modified query with this rel as target. We have to be
* prepared to translate varnos in in_info_list as well as in the
@@ -549,14 +569,12 @@ inheritance_planner(PlannerInfo *root, List *inheritlist)
*/
memcpy(&subroot, root, sizeof(PlannerInfo));
subroot.parse = (Query *)
- adjust_inherited_attrs((Node *) parse,
- parentRTindex, parentOID,
- childRTindex, childOID);
+ adjust_appendrel_attrs((Node *) parse,
+ appinfo);
subroot.in_info_list = (List *)
- adjust_inherited_attrs((Node *) root->in_info_list,
- parentRTindex, parentOID,
- childRTindex, childOID);
- /* There shouldn't be any OJ info to translate, though */
+ adjust_appendrel_attrs((Node *) root->in_info_list,
+ appinfo);
+ /* There shouldn't be any OJ info to translate, as yet */
Assert(subroot.oj_info_list == NIL);
/* Generate plan */
@@ -564,48 +582,23 @@ inheritance_planner(PlannerInfo *root, List *inheritlist)
subplans = lappend(subplans, subplan);
- /*
- * XXX my goodness this next bit is ugly. Really need to think about
- * ways to rein in planner's habit of scribbling on its input.
- *
- * Planning of the subquery might have modified the rangetable, either
- * by addition of RTEs due to expansion of inherited source tables, or
- * by changes of the Query structures inside subquery RTEs. We have
- * to ensure that this gets propagated back to the master copy.
- * However, if we aren't done planning yet, we also need to ensure
- * that subsequent calls to grouping_planner have virgin sub-Queries
- * to work from. So, if we are at the last list entry, just copy the
- * subquery rangetable back to the master copy; if we are not, then
- * extend the master copy by adding whatever the subquery added. (We
- * assume these added entries will go untouched by the future
- * grouping_planner calls. We are also effectively assuming that
- * sub-Queries will get planned identically each time, or at least
- * that the impacts on their rangetables will be the same each time.
- * Did I say this is ugly?)
- */
- if (lnext(l) == NULL)
- parse->rtable = subroot.parse->rtable;
- else
- {
- int subrtlength = list_length(subroot.parse->rtable);
-
- if (subrtlength > mainrtlength)
- {
- List *subrt;
-
- subrt = list_copy_tail(subroot.parse->rtable, mainrtlength);
- parse->rtable = list_concat(parse->rtable, subrt);
- mainrtlength = subrtlength;
- }
- }
-
/* Save preprocessed tlist from first rel for use in Append */
if (tlist == NIL)
tlist = subplan->targetlist;
}
- /* Save the target-relations list for the executor, too */
- parse->resultRelations = inheritlist;
+ /*
+ * Planning might have modified the rangetable, due to changes of the
+ * Query structures inside subquery RTEs. We have to ensure that this
+ * gets propagated back to the master copy. But can't do this until we
+ * are done planning, because all the calls to grouping_planner need
+ * virgin sub-Queries to work from. (We are effectively assuming that
+ * sub-Queries will get planned identically each time, or at least that
+ * the impacts on their rangetables will be the same each time.)
+ *
+ * XXX should clean this up someday
+ */
+ parse->rtable = subroot.parse->rtable;
/* Mark result as unordered (probably unnecessary) */
root->query_pathkeys = NIL;