Commit 7431796b authored by Tom Lane's avatar Tom Lane

fix_parsetree_attnums was not nearly smart enough about walking parse

trees.  Also rewrite find_all_inheritors() in a more intelligible style.
parent 549a8ba5
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.59 1999/12/10 03:55:49 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.60 1999/12/14 03:35:20 tgl Exp $
* *
* NOTES * NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated * The PortalExecutorHeapMemory crap needs to be eliminated
...@@ -340,12 +340,11 @@ PerformAddAttribute(char *relationName, ...@@ -340,12 +340,11 @@ PerformAddAttribute(char *relationName,
{ {
if (inherits) if (inherits)
{ {
Oid childrelid;
List *child, List *child,
*children; *children;
/* this routine is actually in the planner */ /* this routine is actually in the planner */
children = find_all_inheritors(lconsi(myrelid, NIL), NIL); children = find_all_inheritors(myrelid);
/* /*
* find_all_inheritors does the recursive search of the * find_all_inheritors does the recursive search of the
...@@ -354,7 +353,8 @@ PerformAddAttribute(char *relationName, ...@@ -354,7 +353,8 @@ PerformAddAttribute(char *relationName,
*/ */
foreach(child, children) foreach(child, children)
{ {
childrelid = lfirsti(child); Oid childrelid = lfirsti(child);
if (childrelid == myrelid) if (childrelid == myrelid)
continue; continue;
rel = heap_open(childrelid, AccessExclusiveLock); rel = heap_open(childrelid, AccessExclusiveLock);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.37 1999/11/25 00:15:57 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.38 1999/12/14 03:35:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -97,7 +97,7 @@ renameatt(char *relname, ...@@ -97,7 +97,7 @@ renameatt(char *relname,
*children; *children;
/* this routine is actually in the planner */ /* this routine is actually in the planner */
children = find_all_inheritors(lconsi(relid, NIL), NIL); children = find_all_inheritors(relid);
/* /*
* find_all_inheritors does the recursive search of the * find_all_inheritors does the recursive search of the
...@@ -106,10 +106,9 @@ renameatt(char *relname, ...@@ -106,10 +106,9 @@ renameatt(char *relname,
*/ */
foreach(child, children) foreach(child, children)
{ {
Oid childrelid; Oid childrelid = lfirsti(child);
char childname[NAMEDATALEN]; char childname[NAMEDATALEN];
childrelid = lfirsti(child);
if (childrelid == relid) if (childrelid == relid)
continue; continue;
reltup = SearchSysCacheTuple(RELOID, reltup = SearchSysCacheTuple(RELOID,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.39 1999/08/21 03:49:05 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.40 1999/12/14 03:35:24 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "postgres.h" #include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
...@@ -23,17 +24,25 @@ ...@@ -23,17 +24,25 @@
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
typedef struct {
Index rt_index;
int sublevels_up;
Oid old_relid;
Oid new_relid;
} fix_parsetree_attnums_context;
static List *plan_inherit_query(Relids relids, Index rt_index, static List *plan_inherit_query(Relids relids, Index rt_index,
RangeTblEntry *rt_entry, Query *parse, List *tlist, RangeTblEntry *rt_entry, Query *parse, List *tlist,
List **union_rtentriesPtr); List **union_rtentriesPtr);
static RangeTblEntry *new_rangetable_entry(Oid new_relid, static RangeTblEntry *new_rangetable_entry(Oid new_relid,
RangeTblEntry *old_entry); RangeTblEntry *old_entry);
static Query *subst_rangetable(Query *root, Index index,
RangeTblEntry *new_entry);
static void fix_parsetree_attnums(Index rt_index, Oid old_relid, static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
Oid new_relid, Query *parsetree); Oid new_relid, Query *parsetree);
static Append *make_append(List *appendplans, List *unionrtables, Index rt_index, static bool fix_parsetree_attnums_walker (Node *node,
List *inheritrtable, List *tlist); fix_parsetree_attnums_context *context);
static Append *make_append(List *appendplans, List *unionrtables,
Index rt_index,
List *inheritrtable, List *tlist);
/* /*
...@@ -207,7 +216,7 @@ plan_union_queries(Query *parse) ...@@ -207,7 +216,7 @@ plan_union_queries(Query *parse)
/* /*
* plan_inherit_queries * plan_inherit_queries
* *
* Plans the queries for a given parent relation. * Plans the queries for an inheritance tree rooted at a parent relation.
* *
* Inputs: * Inputs:
* parse = parent parse tree * parse = parent parse tree
...@@ -237,13 +246,13 @@ plan_inherit_queries(Query *parse, List *tlist, Index rt_index) ...@@ -237,13 +246,13 @@ plan_inherit_queries(Query *parse, List *tlist, Index rt_index)
List *union_relids; List *union_relids;
List *union_plans; List *union_plans;
union_relids = find_all_inheritors(lconsi(rt_entry->relid, /* Make a list of the target relid plus all its descendants */
NIL), union_relids = find_all_inheritors(rt_entry->relid);
NIL);
/* /*
* Remove the flag for this relation, since we're about to handle it * Remove the flag for this relation, since we're about to handle it.
* (do it before recursing!). XXX destructive change to parent parse tree * XXX destructive change to parent parse tree, but necessary to prevent
* infinite recursion.
*/ */
rt_entry->inh = false; rt_entry->inh = false;
...@@ -259,8 +268,8 @@ plan_inherit_queries(Query *parse, List *tlist, Index rt_index) ...@@ -259,8 +268,8 @@ plan_inherit_queries(Query *parse, List *tlist, Index rt_index)
/* /*
* plan_inherit_query * plan_inherit_query
* Returns a list of plans for 'relids' and a list of range table entries * Returns a list of plans for 'relids', plus a list of range table entries
* in union_rtentries. * in *union_rtentriesPtr.
*/ */
static List * static List *
plan_inherit_query(Relids relids, plan_inherit_query(Relids relids,
...@@ -272,19 +281,31 @@ plan_inherit_query(Relids relids, ...@@ -272,19 +281,31 @@ plan_inherit_query(Relids relids,
{ {
List *union_plans = NIL; List *union_plans = NIL;
List *union_rtentries = NIL; List *union_rtentries = NIL;
List *save_tlist = root->targetList;
List *i; List *i;
/*
* Avoid making copies of the root's tlist, which we aren't going to
* use anyway (we are going to make copies of the passed tlist, instead).
*/
root->targetList = NIL;
foreach(i, relids) foreach(i, relids)
{ {
int relid = lfirsti(i); int relid = lfirsti(i);
/*
* Make a modifiable copy of the original query,
* and replace the target rangetable entry with a new one
* identifying this child table.
*/
Query *new_root = copyObject(root);
RangeTblEntry *new_rt_entry = new_rangetable_entry(relid, RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
rt_entry); rt_entry);
Query *new_root = subst_rangetable(root,
rt_index,
new_rt_entry);
rt_store(rt_index, new_root->rtable, new_rt_entry);
/* /*
* Insert the desired simplified tlist into the subquery * Insert (a modifiable copy of) the desired simplified tlist
* into the subquery
*/ */
new_root->targetList = copyObject(tlist); new_root->targetList = copyObject(tlist);
...@@ -298,7 +319,13 @@ plan_inherit_query(Relids relids, ...@@ -298,7 +319,13 @@ plan_inherit_query(Relids relids,
new_root->havingQual = NULL; new_root->havingQual = NULL;
new_root->hasAggs = false; /* shouldn't be any left ... */ new_root->hasAggs = false; /* shouldn't be any left ... */
/* Fix attribute numbers as necessary */ /*
* Update attribute numbers in case child has different ordering
* of columns than parent (as can happen after ALTER TABLE).
*
* XXX This is a crock, and it doesn't really work. It'd be better
* to fix ALTER TABLE to preserve consistency of attribute numbering.
*/
fix_parsetree_attnums(rt_index, fix_parsetree_attnums(rt_index,
rt_entry->relid, rt_entry->relid,
relid, relid,
...@@ -308,52 +335,56 @@ plan_inherit_query(Relids relids, ...@@ -308,52 +335,56 @@ plan_inherit_query(Relids relids,
union_rtentries = lappend(union_rtentries, new_rt_entry); union_rtentries = lappend(union_rtentries, new_rt_entry);
} }
root->targetList = save_tlist;
*union_rtentriesPtr = union_rtentries; *union_rtentriesPtr = union_rtentries;
return union_plans; return union_plans;
} }
/* /*
* find_all_inheritors - * find_all_inheritors -
* Returns a list of relids corresponding to relations that inherit * Returns an integer list of relids including the given rel plus
* attributes from any relations listed in either of the argument relid * all relations that inherit from it, directly or indirectly.
* lists.
*/ */
List * List *
find_all_inheritors(Relids unexamined_relids, find_all_inheritors(Oid parentrel)
Relids examined_relids)
{ {
List *new_inheritors = NIL; List *examined_relids = NIL;
List *new_examined_relids; List *unexamined_relids = lconsi(parentrel, NIL);
List *new_unexamined_relids;
List *rels;
/* /*
* Find all relations which inherit from members of * While the queue of unexamined relids is nonempty, remove the
* 'unexamined_relids' and store them in 'new_inheritors'. * first element, mark it examined, and find its direct descendants.
* NB: cannot use foreach(), since we modify the queue inside loop.
*/ */
foreach(rels, unexamined_relids) while (unexamined_relids != NIL)
{ {
new_inheritors = LispUnioni(new_inheritors, Oid currentrel = lfirsti(unexamined_relids);
find_inheritance_children(lfirsti(rels))); List *currentchildren;
}
new_examined_relids = LispUnioni(examined_relids, unexamined_relids); unexamined_relids = lnext(unexamined_relids);
new_unexamined_relids = set_differencei(new_inheritors, examined_relids = lappendi(examined_relids, currentrel);
new_examined_relids); currentchildren = find_inheritance_children(currentrel);
/*
* Add to the queue only those children not already seen.
* This could probably be simplified to a plain nconc,
* because our inheritance relationships should always be a
* strict tree, no? Should never find any matches, ISTM...
*/
currentchildren = set_differencei(currentchildren, examined_relids);
unexamined_relids = LispUnioni(unexamined_relids, currentchildren);
}
if (new_unexamined_relids == NIL) return examined_relids;
return new_examined_relids;
else
return find_all_inheritors(new_unexamined_relids,
new_examined_relids);
} }
/* /*
* first_inherit_rt_entry - * first_inherit_rt_entry -
* Given a rangetable, find the first rangetable entry that represents * Given a rangetable, find the first rangetable entry that represents
* the appropriate special case. * an inheritance set.
* *
* Returns a rangetable index., Returns -1 if no matches * Returns a rangetable index (1..n).
* Returns -1 if no matches
*/ */
int int
first_inherit_rt_entry(List *rangetable) first_inherit_rt_entry(List *rangetable)
...@@ -365,9 +396,9 @@ first_inherit_rt_entry(List *rangetable) ...@@ -365,9 +396,9 @@ first_inherit_rt_entry(List *rangetable)
{ {
RangeTblEntry *rt_entry = lfirst(temp); RangeTblEntry *rt_entry = lfirst(temp);
if (rt_entry->inh)
return count + 1;
count++; count++;
if (rt_entry->inh)
return count;
} }
return -1; return -1;
...@@ -397,23 +428,35 @@ new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry) ...@@ -397,23 +428,35 @@ new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
} }
/* /*
* subst_rangetable * fix_parsetree_attnums
* Replaces the 'index'th rangetable entry in 'root' with 'new_entry'. * Replaces attribute numbers from the relation represented by
* 'old_relid' in 'parsetree' with the attribute numbers from
* 'new_relid'.
* *
* Returns a new copy of 'root'. * The parsetree is MODIFIED IN PLACE. This is OK only because
* plan_inherit_query made a copy of the tree for us to hack upon.
*/ */
static Query * static void
subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry) fix_parsetree_attnums(Index rt_index,
Oid old_relid,
Oid new_relid,
Query *parsetree)
{ {
Query *new_root = copyObject(root); fix_parsetree_attnums_context context;
List *temp;
int i;
for (temp = new_root->rtable, i = 1; i < index; temp = lnext(temp), i++) if (old_relid == new_relid)
; return; /* no work needed for parent rel itself */
lfirst(temp) = new_entry;
return new_root; context.rt_index = rt_index;
context.old_relid = old_relid;
context.new_relid = new_relid;
context.sublevels_up = 0;
/*
* We must scan both the targetlist and qual, but we know the
* havingQual is empty, so we can ignore it.
*/
fix_parsetree_attnums_walker((Node *) parsetree->targetList, &context);
fix_parsetree_attnums_walker((Node *) parsetree->qual, &context);
} }
/* /*
...@@ -425,82 +468,60 @@ subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry) ...@@ -425,82 +468,60 @@ subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry)
* for inherited attributes. It'd be better to rip this code out and fix * for inherited attributes. It'd be better to rip this code out and fix
* ALTER TABLE... * ALTER TABLE...
*/ */
static void static bool
fix_parsetree_attnums_nodes(Index rt_index, fix_parsetree_attnums_walker (Node *node,
Oid old_relid, fix_parsetree_attnums_context *context)
Oid new_relid,
Node *node)
{ {
if (node == NULL) if (node == NULL)
return; return false;
if (IsA(node, Var))
switch (nodeTag(node))
{ {
case T_TargetEntry: Var *var = (Var *) node;
{
TargetEntry *tle = (TargetEntry *) node;
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
tle->expr);
}
break;
case T_Expr:
{
Expr *expr = (Expr *) node;
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
(Node *) expr->args);
}
break;
case T_Var:
{
Var *var = (Var *) node;
if (var->varno == rt_index && var->varattno != 0)
{
var->varattno = get_attnum(new_relid,
get_attname(old_relid, var->varattno));
}
}
break;
case T_List:
{
List *l;
foreach(l, (List *) node)
{
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
(Node *) lfirst(l));
}
}
break;
default:
break;
}
}
/* if (var->varlevelsup == context->sublevels_up &&
* fix_parsetree_attnums var->varno == context->rt_index &&
* Replaces attribute numbers from the relation represented by var->varattno > 0)
* 'old_relid' in 'parsetree' with the attribute numbers from {
* 'new_relid'. var->varattno = get_attnum(context->new_relid,
* get_attname(context->old_relid,
* Returns the destructively_modified parsetree. var->varattno));
* }
*/ return false;
static void }
fix_parsetree_attnums(Index rt_index, if (IsA(node, SubLink))
Oid old_relid, {
Oid new_relid, /*
Query *parsetree) * Standard expression_tree_walker will not recurse into subselect,
{ * but here we must do so.
if (old_relid == new_relid) */
return; SubLink *sub = (SubLink *) node;
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, if (fix_parsetree_attnums_walker((Node *) (sub->lefthand), context))
(Node *) parsetree->targetList); return true;
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid, context->sublevels_up++;
parsetree->qual); if (fix_parsetree_attnums_walker((Node *) (sub->subselect), context))
{
context->sublevels_up--;
return true;
}
context->sublevels_up--;
return false;
}
if (IsA(node, Query))
{
/* Reach here after recursing down into subselect above... */
Query *qry = (Query *) node;
if (fix_parsetree_attnums_walker((Node *) (qry->targetList), context))
return true;
if (fix_parsetree_attnums_walker((Node *) (qry->qual), context))
return true;
if (fix_parsetree_attnums_walker((Node *) (qry->havingQual), context))
return true;
return false;
}
return expression_tree_walker(node, fix_parsetree_attnums_walker,
(void *) context);
} }
static Append * static Append *
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: prep.h,v 1.19 1999/09/13 00:17:08 tgl Exp $ * $Id: prep.h,v 1.20 1999/12/14 03:35:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -32,8 +32,7 @@ extern List *preprocess_targetlist(List *tlist, int command_type, ...@@ -32,8 +32,7 @@ extern List *preprocess_targetlist(List *tlist, int command_type,
/* /*
* prototypes for prepunion.c * prototypes for prepunion.c
*/ */
extern List *find_all_inheritors(List *unexamined_relids, extern List *find_all_inheritors(Oid parentrel);
List *examined_relids);
extern int first_inherit_rt_entry(List *rangetable); extern int first_inherit_rt_entry(List *rangetable);
extern Append *plan_union_queries(Query *parse); extern Append *plan_union_queries(Query *parse);
extern Append *plan_inherit_queries(Query *parse, List *tlist, Index rt_index); extern Append *plan_inherit_queries(Query *parse, List *tlist, Index rt_index);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment