aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/command.c20
-rw-r--r--src/backend/commands/copy.c27
-rw-r--r--src/backend/commands/explain.c16
-rw-r--r--src/backend/executor/execMain.c376
-rw-r--r--src/backend/executor/execQual.c3
-rw-r--r--src/backend/executor/execTuples.c20
-rw-r--r--src/backend/executor/execUtils.c40
-rw-r--r--src/backend/executor/functions.c3
-rw-r--r--src/backend/executor/nodeAppend.c194
-rw-r--r--src/backend/executor/nodeSeqscan.c4
-rw-r--r--src/backend/nodes/copyfuncs.c34
-rw-r--r--src/backend/nodes/equalfuncs.c43
-rw-r--r--src/backend/nodes/outfuncs.c61
-rw-r--r--src/backend/nodes/readfuncs.c104
-rw-r--r--src/backend/optimizer/README21
-rw-r--r--src/backend/optimizer/path/allpaths.c191
-rw-r--r--src/backend/optimizer/path/pathkeys.c6
-rw-r--r--src/backend/optimizer/plan/createplan.c392
-rw-r--r--src/backend/optimizer/plan/planmain.c20
-rw-r--r--src/backend/optimizer/plan/planner.c169
-rw-r--r--src/backend/optimizer/prep/prepunion.c473
-rw-r--r--src/backend/optimizer/util/pathnode.c33
-rw-r--r--src/backend/optimizer/util/relnode.c30
-rw-r--r--src/backend/parser/parse_clause.c8
-rw-r--r--src/backend/tcop/pquery.c9
-rw-r--r--src/include/catalog/catversion.h6
-rw-r--r--src/include/executor/executor.h8
-rw-r--r--src/include/executor/tuptable.h3
-rw-r--r--src/include/nodes/execnodes.h85
-rw-r--r--src/include/nodes/nodes.h7
-rw-r--r--src/include/nodes/parsenodes.h12
-rw-r--r--src/include/nodes/plannodes.h24
-rw-r--r--src/include/nodes/relation.h24
-rw-r--r--src/include/optimizer/pathnode.h4
-rw-r--r--src/include/optimizer/planmain.h4
-rw-r--r--src/include/optimizer/planner.h3
-rw-r--r--src/include/optimizer/prep.h12
37 files changed, 1247 insertions, 1242 deletions
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 54b913dcac1..073360c1e4a 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.109 2000/11/08 22:09:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.110 2000/11/12 00:36:56 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@@ -1098,13 +1098,12 @@ AlterTableAddConstraint(char *relationName,
case CONSTR_CHECK:
{
ParseState *pstate;
- bool successful = TRUE;
+ bool successful = true;
HeapScanDesc scan;
ExprContext *econtext;
TupleTableSlot *slot = makeNode(TupleTableSlot);
HeapTuple tuple;
RangeTblEntry *rte;
- List *rtlist;
List *qual;
List *constlist;
Relation rel;
@@ -1112,9 +1111,9 @@ AlterTableAddConstraint(char *relationName,
char *name;
if (constr->name)
- name=constr->name;
+ name = constr->name;
else
- name="<unnamed>";
+ name = "<unnamed>";
constlist = makeList1(constr);
@@ -1169,13 +1168,6 @@ AlterTableAddConstraint(char *relationName,
qual = makeList1(expr);
- rte = makeNode(RangeTblEntry);
- rte->relname = relationName;
- rte->relid = RelationGetRelid(rel);
- rte->eref = makeNode(Attr);
- rte->eref->relname = relationName;
- rtlist = makeList1(rte);
-
/*
* Scan through the rows now, making the necessary things
* for ExecQual, and then call it to evaluate the
@@ -1188,10 +1180,8 @@ AlterTableAddConstraint(char *relationName,
slot->ttc_descIsNew = true;
slot->ttc_tupleDescriptor = rel->rd_att;
slot->ttc_buffer = InvalidBuffer;
- slot->ttc_whichplan = -1;
econtext = MakeExprContext(slot, CurrentMemoryContext);
- econtext->ecxt_range_table = rtlist; /* range table */
if (!ExecQual(qual, econtext, true))
{
successful=false;
@@ -1201,8 +1191,6 @@ AlterTableAddConstraint(char *relationName,
}
pfree(slot);
- pfree(rtlist);
- pfree(rte);
heap_endscan(scan);
heap_close(rel, NoLock);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index ea90e0f2e04..2877999500c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.122 2000/09/06 14:15:16 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.123 2000/11/12 00:36:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -597,7 +597,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
int32 ntuples,
tuples_read = 0;
bool reading_to_eof = true;
- RelationInfo *relationInfo;
+ ResultRelInfo *resultRelInfo;
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
TupleTable tupleTable;
TupleTableSlot *slot;
@@ -609,20 +609,19 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
attr_count = tupDesc->natts;
/*
- * We need a RelationInfo so we can use the regular executor's
+ * We need a ResultRelInfo so we can use the regular executor's
* index-entry-making machinery. (There used to be a huge amount
* of code here that basically duplicated execUtils.c ...)
*/
- relationInfo = makeNode(RelationInfo);
- relationInfo->ri_RangeTableIndex = 1; /* dummy */
- relationInfo->ri_RelationDesc = rel;
- relationInfo->ri_NumIndices = 0;
- relationInfo->ri_IndexRelationDescs = NULL;
- relationInfo->ri_IndexRelationInfo = NULL;
+ resultRelInfo = makeNode(ResultRelInfo);
+ resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
+ resultRelInfo->ri_RelationDesc = rel;
- ExecOpenIndices(relationInfo);
+ ExecOpenIndices(resultRelInfo);
- estate->es_result_relation_info = relationInfo;
+ estate->es_result_relations = resultRelInfo;
+ estate->es_num_result_relations = 1;
+ estate->es_result_relation_info = resultRelInfo;
/* Set up a dummy tuple table too */
tupleTable = ExecCreateTupleTable(1);
@@ -830,7 +829,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
if (rel->rd_att->constr)
- ExecConstraints("CopyFrom", rel, slot, estate);
+ ExecConstraints("CopyFrom", resultRelInfo, slot, estate);
/* ----------------
* OK, store the tuple and create index entries for it
@@ -838,7 +837,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
*/
heap_insert(rel, tuple);
- if (relationInfo->ri_NumIndices > 0)
+ if (resultRelInfo->ri_NumIndices > 0)
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
/* AFTER ROW INSERT Triggers */
@@ -886,7 +885,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
ExecDropTupleTable(tupleTable, true);
- ExecCloseIndices(relationInfo);
+ ExecCloseIndices(resultRelInfo);
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 6976278c1d0..b76d45480f2 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.61 2000/10/26 21:34:44 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.62 2000/11/12 00:36:56 tgl Exp $
*
*/
@@ -327,32 +327,18 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
if (IsA(plan, Append))
{
Append *appendplan = (Append *) plan;
- List *saved_rtable = es->rtable;
- int whichplan = 0;
List *lst;
foreach(lst, appendplan->appendplans)
{
Plan *subnode = (Plan *) lfirst(lst);
- if (appendplan->inheritrelid > 0)
- {
- RangeTblEntry *rtentry;
-
- rtentry = nth(whichplan, appendplan->inheritrtable);
- Assert(rtentry != NULL);
- rt_store(appendplan->inheritrelid, es->rtable, rtentry);
- }
-
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode, indent + 3, es);
-
- whichplan++;
}
- es->rtable = saved_rtable;
}
if (IsA(plan, SubqueryScan))
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index a26acc9a763..d9d02654970 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.131 2000/10/26 21:35:15 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.132 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -50,6 +50,10 @@ static TupleDesc InitPlan(CmdType operation,
Query *parseTree,
Plan *plan,
EState *estate);
+static void initResultRelInfo(ResultRelInfo *resultRelInfo,
+ Index resultRelationIndex,
+ List *rangeTable,
+ CmdType operation);
static void EndPlan(Plan *plan, EState *estate);
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
CmdType operation,
@@ -310,10 +314,6 @@ ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
* ExecCheckPlanPerms
* Recursively scan the plan tree to check access permissions in
* subplans.
- *
- * We also need to look at the local rangetables in Append plan nodes,
- * which is pretty bogus --- most likely, those tables should be mentioned
- * in the query's main rangetable. But at the moment, they're not.
*/
static void
ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
@@ -365,27 +365,11 @@ ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
Append *app = (Append *) plan;
List *appendplans;
- if (app->inheritrelid > 0)
+ foreach(appendplans, app->appendplans)
{
- /* Append implements expansion of inheritance */
- ExecCheckRTPerms(app->inheritrtable, operation);
-
- foreach(appendplans, app->appendplans)
- {
- ExecCheckPlanPerms((Plan *) lfirst(appendplans),
- rangeTable,
- operation);
- }
- }
- else
- {
- /* Append implements UNION, which must be a SELECT */
- foreach(appendplans, app->appendplans)
- {
- ExecCheckPlanPerms((Plan *) lfirst(appendplans),
- rangeTable,
- CMD_SELECT);
- }
+ ExecCheckPlanPerms((Plan *) lfirst(appendplans),
+ rangeTable,
+ operation);
}
break;
}
@@ -518,10 +502,8 @@ static TupleDesc
InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
{
List *rangeTable;
- int resultRelation;
Relation intoRelationDesc;
TupleDesc tupType;
- List *targetList;
/*
* Do permissions checks.
@@ -532,7 +514,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
* get information from query descriptor
*/
rangeTable = parseTree->rtable;
- resultRelation = parseTree->resultRelation;
/*
* initialize the node's execution state
@@ -540,63 +521,61 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
estate->es_range_table = rangeTable;
/*
- * initialize result relation stuff
+ * if there is a result relation, initialize result relation stuff
*/
-
- if (resultRelation != 0 && operation != CMD_SELECT)
+ if (parseTree->resultRelation != 0 && operation != CMD_SELECT)
{
+ List *resultRelations = parseTree->resultRelations;
+ int numResultRelations;
+ ResultRelInfo *resultRelInfos;
- /*
- * if we have a result relation, open it and initialize the result
- * relation info stuff.
- */
- RelationInfo *resultRelationInfo;
- Index resultRelationIndex;
- Oid resultRelationOid;
- Relation resultRelationDesc;
-
- resultRelationIndex = resultRelation;
- resultRelationOid = getrelid(resultRelationIndex, rangeTable);
- resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);
-
- if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
- elog(ERROR, "You can't change sequence relation %s",
- RelationGetRelationName(resultRelationDesc));
-
- if (resultRelationDesc->rd_rel->relkind == RELKIND_TOASTVALUE)
- elog(ERROR, "You can't change toast relation %s",
- RelationGetRelationName(resultRelationDesc));
-
- if (resultRelationDesc->rd_rel->relkind == RELKIND_VIEW)
- elog(ERROR, "You can't change view relation %s",
- RelationGetRelationName(resultRelationDesc));
-
- resultRelationInfo = makeNode(RelationInfo);
- resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
- resultRelationInfo->ri_RelationDesc = resultRelationDesc;
- resultRelationInfo->ri_NumIndices = 0;
- resultRelationInfo->ri_IndexRelationDescs = NULL;
- resultRelationInfo->ri_IndexRelationInfo = NULL;
+ if (resultRelations != NIL)
+ {
+ /*
+ * Multiple result relations (due to inheritance)
+ * parseTree->resultRelations identifies them all
+ */
+ ResultRelInfo *resultRelInfo;
- /*
- * If there are indices on the result relation, open them and save
- * descriptors in the result relation info, so that we can add new
- * index entries for the tuples we add/update. We need not do
- * this for a DELETE, however, since deletion doesn't affect
- * indexes.
- */
- if (resultRelationDesc->rd_rel->relhasindex &&
- operation != CMD_DELETE)
- ExecOpenIndices(resultRelationInfo);
+ numResultRelations = length(resultRelations);
+ resultRelInfos = (ResultRelInfo *)
+ palloc(numResultRelations * sizeof(ResultRelInfo));
+ resultRelInfo = resultRelInfos;
+ while (resultRelations != NIL)
+ {
+ initResultRelInfo(resultRelInfo,
+ lfirsti(resultRelations),
+ rangeTable,
+ operation);
+ resultRelInfo++;
+ resultRelations = lnext(resultRelations);
+ }
+ }
+ else
+ {
+ /*
+ * Single result relation identified by parseTree->resultRelation
+ */
+ numResultRelations = 1;
+ resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
+ initResultRelInfo(resultRelInfos,
+ parseTree->resultRelation,
+ rangeTable,
+ operation);
+ }
- estate->es_result_relation_info = resultRelationInfo;
+ estate->es_result_relations = resultRelInfos;
+ estate->es_num_result_relations = numResultRelations;
+ /* Initialize to first or only result rel */
+ estate->es_result_relation_info = resultRelInfos;
}
else
{
-
/*
* if no result relation, then set state appropriately
*/
+ estate->es_result_relations = NULL;
+ estate->es_num_result_relations = 0;
estate->es_result_relation_info = NULL;
}
@@ -642,19 +621,17 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
ExecInitNode(plan, estate, NULL);
/*
- * get the tuple descriptor describing the type of tuples to return..
+ * Get the tuple descriptor describing the type of tuples to return.
* (this is especially important if we are creating a relation with
* "retrieve into")
*/
tupType = ExecGetTupType(plan); /* tuple descriptor */
- targetList = plan->targetlist;
/*
- * Now that we have the target list, initialize the junk filter if
- * needed. SELECT and INSERT queries need a filter if there are any
- * junk attrs in the tlist. UPDATE and DELETE always need one, since
- * there's always a junk 'ctid' attribute present --- no need to look
- * first.
+ * Initialize the junk filter if needed. SELECT and INSERT queries need
+ * a filter if there are any junk attrs in the tlist. UPDATE and
+ * DELETE always need one, since there's always a junk 'ctid' attribute
+ * present --- no need to look first.
*/
{
bool junk_filter_needed = false;
@@ -664,7 +641,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
{
case CMD_SELECT:
case CMD_INSERT:
- foreach(tlist, targetList)
+ foreach(tlist, plan->targetlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(tlist);
@@ -685,12 +662,55 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
if (junk_filter_needed)
{
- JunkFilter *j = ExecInitJunkFilter(targetList, tupType);
+ /*
+ * If there are multiple result relations, each one needs
+ * its own junk filter. Note this is only possible for
+ * UPDATE/DELETE, so we can't be fooled by some needing
+ * a filter and some not.
+ */
+ if (parseTree->resultRelations != NIL)
+ {
+ List *subplans;
+ ResultRelInfo *resultRelInfo;
+
+ /* Top plan had better be an Append here. */
+ Assert(IsA(plan, Append));
+ Assert(((Append *) plan)->isTarget);
+ subplans = ((Append *) plan)->appendplans;
+ Assert(length(subplans) == estate->es_num_result_relations);
+ resultRelInfo = estate->es_result_relations;
+ while (subplans != NIL)
+ {
+ Plan *subplan = (Plan *) lfirst(subplans);
+ JunkFilter *j;
+
+ j = ExecInitJunkFilter(subplan->targetlist,
+ ExecGetTupType(subplan));
+ resultRelInfo->ri_junkFilter = j;
+ resultRelInfo++;
+ subplans = lnext(subplans);
+ }
+ /*
+ * Set active junkfilter too; at this point ExecInitAppend
+ * has already selected an active result relation...
+ */
+ estate->es_junkFilter =
+ estate->es_result_relation_info->ri_junkFilter;
+ }
+ else
+ {
+ /* Normal case with just one JunkFilter */
+ JunkFilter *j = ExecInitJunkFilter(plan->targetlist,
+ tupType);
- estate->es_junkFilter = j;
+ estate->es_junkFilter = j;
+ if (estate->es_result_relation_info)
+ estate->es_result_relation_info->ri_junkFilter = j;
- if (operation == CMD_SELECT)
- tupType = j->jf_cleanTupType;
+ /* For SELECT, want to return the cleaned tuple type */
+ if (operation == CMD_SELECT)
+ tupType = j->jf_cleanTupType;
+ }
}
else
estate->es_junkFilter = NULL;
@@ -762,6 +782,59 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
return tupType;
}
+/*
+ * Initialize ResultRelInfo data for one result relation
+ */
+static void
+initResultRelInfo(ResultRelInfo *resultRelInfo,
+ Index resultRelationIndex,
+ List *rangeTable,
+ CmdType operation)
+{
+ Oid resultRelationOid;
+ Relation resultRelationDesc;
+
+ resultRelationOid = getrelid(resultRelationIndex, rangeTable);
+ resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);
+
+ switch (resultRelationDesc->rd_rel->relkind)
+ {
+ case RELKIND_SEQUENCE:
+ elog(ERROR, "You can't change sequence relation %s",
+ RelationGetRelationName(resultRelationDesc));
+ break;
+ case RELKIND_TOASTVALUE:
+ elog(ERROR, "You can't change toast relation %s",
+ RelationGetRelationName(resultRelationDesc));
+ break;
+ case RELKIND_VIEW:
+ elog(ERROR, "You can't change view relation %s",
+ RelationGetRelationName(resultRelationDesc));
+ break;
+ }
+
+ MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
+ resultRelInfo->type = T_ResultRelInfo;
+ resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
+ resultRelInfo->ri_RelationDesc = resultRelationDesc;
+ resultRelInfo->ri_NumIndices = 0;
+ resultRelInfo->ri_IndexRelationDescs = NULL;
+ resultRelInfo->ri_IndexRelationInfo = NULL;
+ resultRelInfo->ri_ConstraintExprs = NULL;
+ resultRelInfo->ri_junkFilter = NULL;
+
+ /*
+ * If there are indices on the result relation, open them and save
+ * descriptors in the result relation info, so that we can add new
+ * index entries for the tuples we add/update. We need not do
+ * this for a DELETE, however, since deletion doesn't affect
+ * indexes.
+ */
+ if (resultRelationDesc->rd_rel->relhasindex &&
+ operation != CMD_DELETE)
+ ExecOpenIndices(resultRelInfo);
+}
+
/* ----------------------------------------------------------------
* EndPlan
*
@@ -771,7 +844,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
static void
EndPlan(Plan *plan, EState *estate)
{
- RelationInfo *resultRelationInfo;
+ ResultRelInfo *resultRelInfo;
+ int i;
List *l;
/*
@@ -792,16 +866,16 @@ EndPlan(Plan *plan, EState *estate)
estate->es_tupleTable = NULL;
/*
- * close the result relation if necessary, but hold lock on it
- * until xact commit. NB: must not do this till after ExecEndNode(),
- * see nodeAppend.c ...
+ * close the result relation(s) if any, but hold locks
+ * until xact commit.
*/
- resultRelationInfo = estate->es_result_relation_info;
- if (resultRelationInfo != NULL)
+ resultRelInfo = estate->es_result_relations;
+ for (i = estate->es_num_result_relations; i > 0; i--)
{
- heap_close(resultRelationInfo->ri_RelationDesc, NoLock);
- /* close indices on the result relation, too */
- ExecCloseIndices(resultRelationInfo);
+ /* Close indices and then the relation itself */
+ ExecCloseIndices(resultRelInfo);
+ heap_close(resultRelInfo->ri_RelationDesc, NoLock);
+ resultRelInfo++;
}
/*
@@ -1116,7 +1190,7 @@ ExecAppend(TupleTableSlot *slot,
EState *estate)
{
HeapTuple tuple;
- RelationInfo *resultRelationInfo;
+ ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
int numIndices;
Oid newId;
@@ -1127,10 +1201,10 @@ ExecAppend(TupleTableSlot *slot,
tuple = slot->val;
/*
- * get information on the result relation
+ * get information on the (current) result relation
*/
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+ resultRelInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW INSERT Triggers */
if (resultRelationDesc->trigdesc &&
@@ -1154,9 +1228,8 @@ ExecAppend(TupleTableSlot *slot,
/*
* Check the constraints of the tuple
*/
-
if (resultRelationDesc->rd_att->constr)
- ExecConstraints("ExecAppend", resultRelationDesc, slot, estate);
+ ExecConstraints("ExecAppend", resultRelInfo, slot, estate);
/*
* insert the tuple
@@ -1174,7 +1247,7 @@ ExecAppend(TupleTableSlot *slot,
* the tupleid of the new tuple is placed in the new tuple's t_ctid
* field.
*/
- numIndices = resultRelationInfo->ri_NumIndices;
+ numIndices = resultRelInfo->ri_NumIndices;
if (numIndices > 0)
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
@@ -1195,16 +1268,16 @@ ExecDelete(TupleTableSlot *slot,
ItemPointer tupleid,
EState *estate)
{
- RelationInfo *resultRelationInfo;
+ ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
ItemPointerData ctid;
int result;
/*
- * get the result relation information
+ * get information on the (current) result relation
*/
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+ resultRelInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW DELETE Triggers */
if (resultRelationDesc->trigdesc &&
@@ -1237,7 +1310,7 @@ ldelete:;
else if (!(ItemPointerEquals(tupleid, &ctid)))
{
TupleTableSlot *epqslot = EvalPlanQual(estate,
- resultRelationInfo->ri_RangeTableIndex, &ctid);
+ resultRelInfo->ri_RangeTableIndex, &ctid);
if (!TupIsNull(epqslot))
{
@@ -1287,7 +1360,7 @@ ExecReplace(TupleTableSlot *slot,
EState *estate)
{
HeapTuple tuple;
- RelationInfo *resultRelationInfo;
+ ResultRelInfo *resultRelInfo;
Relation resultRelationDesc;
ItemPointerData ctid;
int result;
@@ -1308,10 +1381,10 @@ ExecReplace(TupleTableSlot *slot,
tuple = slot->val;
/*
- * get the result relation information
+ * get information on the (current) result relation
*/
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+ resultRelInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelInfo->ri_RelationDesc;
/* BEFORE ROW UPDATE Triggers */
if (resultRelationDesc->trigdesc &&
@@ -1335,9 +1408,8 @@ ExecReplace(TupleTableSlot *slot,
/*
* Check the constraints of the tuple
*/
-
if (resultRelationDesc->rd_att->constr)
- ExecConstraints("ExecReplace", resultRelationDesc, slot, estate);
+ ExecConstraints("ExecReplace", resultRelInfo, slot, estate);
/*
* replace the heap tuple
@@ -1358,7 +1430,7 @@ lreplace:;
else if (!(ItemPointerEquals(tupleid, &ctid)))
{
TupleTableSlot *epqslot = EvalPlanQual(estate,
- resultRelationInfo->ri_RangeTableIndex, &ctid);
+ resultRelInfo->ri_RangeTableIndex, &ctid);
if (!TupIsNull(epqslot))
{
@@ -1396,7 +1468,7 @@ lreplace:;
* there.
*/
- numIndices = resultRelationInfo->ri_NumIndices;
+ numIndices = resultRelInfo->ri_NumIndices;
if (numIndices > 0)
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true);
@@ -1406,8 +1478,10 @@ lreplace:;
}
static char *
-ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
+ExecRelCheck(ResultRelInfo *resultRelInfo,
+ TupleTableSlot *slot, EState *estate)
{
+ Relation rel = resultRelInfo->ri_RelationDesc;
int ncheck = rel->rd_att->constr->num_check;
ConstrCheck *check = rel->rd_att->constr->check;
ExprContext *econtext;
@@ -1416,6 +1490,24 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
int i;
/*
+ * If first time through for this result relation, build expression
+ * nodetrees for rel's constraint expressions. Keep them in the
+ * per-query memory context so they'll survive throughout the query.
+ */
+ if (resultRelInfo->ri_ConstraintExprs == NULL)
+ {
+ oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
+ resultRelInfo->ri_ConstraintExprs =
+ (List **) palloc(ncheck * sizeof(List *));
+ for (i = 0; i < ncheck; i++)
+ {
+ qual = (List *) stringToNode(check[i].ccbin);
+ resultRelInfo->ri_ConstraintExprs[i] = qual;
+ }
+ MemoryContextSwitchTo(oldContext);
+ }
+
+ /*
* We will use the EState's per-tuple context for evaluating constraint
* expressions. Create it if it's not already there; if it is, reset it
* to free previously-used storage.
@@ -1431,58 +1523,13 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
else
ResetExprContext(econtext);
- /*
- * If first time through for current result relation, set up econtext's
- * range table to refer to result rel, and build expression nodetrees
- * for rel's constraint expressions. All this stuff is kept in the
- * per-query memory context so it will still be here next time through.
- *
- * NOTE: if there are multiple result relations (eg, due to inheritance)
- * then we leak storage for prior rel's expressions and rangetable.
- * This should not be a big problem as long as result rels are processed
- * sequentially within a command.
- */
- if (econtext->ecxt_range_table == NIL ||
- getrelid(1, econtext->ecxt_range_table) != RelationGetRelid(rel))
- {
- RangeTblEntry *rte;
-
- /*
- * Make sure expressions, etc are placed in appropriate context.
- */
- oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
-
- rte = makeNode(RangeTblEntry);
-
- rte->relname = RelationGetRelationName(rel);
- rte->relid = RelationGetRelid(rel);
- rte->eref = makeNode(Attr);
- rte->eref->relname = rte->relname;
- /* other fields won't be used, leave them zero */
-
- /* Set up single-entry range table */
- econtext->ecxt_range_table = makeList1(rte);
-
- estate->es_result_relation_constraints =
- (List **) palloc(ncheck * sizeof(List *));
-
- for (i = 0; i < ncheck; i++)
- {
- qual = (List *) stringToNode(check[i].ccbin);
- estate->es_result_relation_constraints[i] = qual;
- }
-
- /* Done with building long-lived items */
- MemoryContextSwitchTo(oldContext);
- }
-
/* Arrange for econtext's scan tuple to be the tuple under test */
econtext->ecxt_scantuple = slot;
/* And evaluate the constraints */
for (i = 0; i < ncheck; i++)
{
- qual = estate->es_result_relation_constraints[i];
+ qual = resultRelInfo->ri_ConstraintExprs[i];
/*
* NOTE: SQL92 specifies that a NULL result from a constraint
@@ -1498,9 +1545,10 @@ ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate)
}
void
-ExecConstraints(char *caller, Relation rel,
+ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate)
{
+ Relation rel = resultRelInfo->ri_RelationDesc;
HeapTuple tuple = slot->val;
TupleConstr *constr = rel->rd_att->constr;
@@ -1524,7 +1572,7 @@ ExecConstraints(char *caller, Relation rel,
{
char *failed;
- if ((failed = ExecRelCheck(rel, slot, estate)) != NULL)
+ if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
elog(ERROR, "%s: rejected due to CHECK constraint %s",
caller, failed);
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 622ea2ef82c..beeff0db331 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.80 2000/08/24 23:34:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.81 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -341,7 +341,6 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
tempSlot->ttc_descIsNew = true;
tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL;
tempSlot->ttc_buffer = InvalidBuffer;
- tempSlot->ttc_whichplan = -1;
tup = heap_copytuple(heapTuple);
td = CreateTupleDescCopy(tuple_type);
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 408716abf83..65eef4141f4 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.42 2000/10/26 21:35:15 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.43 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -303,7 +303,6 @@ ExecAllocTableSlot(TupleTable table)
slot->ttc_descIsNew = true;
slot->ttc_tupleDescriptor = (TupleDesc) NULL;
slot->ttc_buffer = InvalidBuffer;
- slot->ttc_whichplan = -1;
return slot;
}
@@ -675,20 +674,11 @@ NodeGetResultTupleSlot(Plan *node)
case T_Append:
{
- Append *n = (Append *) node;
- AppendState *appendstate;
- List *appendplans;
- int whichplan;
- Plan *subplan;
-
- appendstate = n->appendstate;
- appendplans = n->appendplans;
- whichplan = appendstate->as_whichplan;
-
- subplan = (Plan *) nth(whichplan, appendplans);
- slot = NodeGetResultTupleSlot(subplan);
- break;
+ AppendState *appendstate = ((Append *) node)->appendstate;
+
+ slot = appendstate->cstate.cs_ResultTupleSlot;
}
+ break;
case T_IndexScan:
{
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 4eff4a07bb2..ecdda594188 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.67 2000/10/05 19:48:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.68 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -172,7 +172,6 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
econtext->ecxt_param_list_info = estate->es_param_list_info;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
- econtext->ecxt_range_table = estate->es_range_table;
commonstate->cs_ExprContext = econtext;
}
@@ -215,7 +214,6 @@ MakeExprContext(TupleTableSlot *slot,
econtext->ecxt_param_list_info = NULL;
econtext->ecxt_aggvalues = NULL;
econtext->ecxt_aggnulls = NULL;
- econtext->ecxt_range_table = NIL;
return econtext;
}
@@ -649,10 +647,10 @@ QueryDescGetTypeInfo(QueryDesc *queryDesc)
* ExecOpenIndices
*
* Find the indices associated with a result relation, open them,
- * and save information about them in the result RelationInfo.
+ * and save information about them in the result ResultRelInfo.
*
* At entry, caller has already opened and locked
- * resultRelationInfo->ri_RelationDesc.
+ * resultRelInfo->ri_RelationDesc.
*
* This used to be horribly ugly code, and slow too because it
* did a sequential scan of pg_index. Now we rely on the relcache
@@ -662,9 +660,9 @@ QueryDescGetTypeInfo(QueryDesc *queryDesc)
* ----------------------------------------------------------------
*/
void
-ExecOpenIndices(RelationInfo *resultRelationInfo)
+ExecOpenIndices(ResultRelInfo *resultRelInfo)
{
- Relation resultRelation = resultRelationInfo->ri_RelationDesc;
+ Relation resultRelation = resultRelInfo->ri_RelationDesc;
List *indexoidlist,
*indexoidscan;
int len,
@@ -672,7 +670,7 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
RelationPtr relationDescs;
IndexInfo **indexInfoArray;
- resultRelationInfo->ri_NumIndices = 0;
+ resultRelInfo->ri_NumIndices = 0;
/* checks for disabled indexes */
if (! RelationGetForm(resultRelation)->relhasindex)
@@ -697,9 +695,9 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));
- resultRelationInfo->ri_NumIndices = len;
- resultRelationInfo->ri_IndexRelationDescs = relationDescs;
- resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
+ resultRelInfo->ri_NumIndices = len;
+ resultRelInfo->ri_IndexRelationDescs = relationDescs;
+ resultRelInfo->ri_IndexRelationInfo = indexInfoArray;
/* ----------------
* For each index, open the index relation and save pg_index info.
@@ -765,18 +763,18 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
/* ----------------------------------------------------------------
* ExecCloseIndices
*
- * Close the index relations stored in resultRelationInfo
+ * Close the index relations stored in resultRelInfo
* ----------------------------------------------------------------
*/
void
-ExecCloseIndices(RelationInfo *resultRelationInfo)
+ExecCloseIndices(ResultRelInfo *resultRelInfo)
{
int i;
int numIndices;
RelationPtr relationDescs;
- numIndices = resultRelationInfo->ri_NumIndices;
- relationDescs = resultRelationInfo->ri_IndexRelationDescs;
+ numIndices = resultRelInfo->ri_NumIndices;
+ relationDescs = resultRelInfo->ri_IndexRelationDescs;
for (i = 0; i < numIndices; i++)
{
@@ -817,7 +815,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
bool is_update)
{
HeapTuple heapTuple;
- RelationInfo *resultRelationInfo;
+ ResultRelInfo *resultRelInfo;
int i;
int numIndices;
RelationPtr relationDescs;
@@ -833,11 +831,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
/*
* Get information from the result relation info structure.
*/
- resultRelationInfo = estate->es_result_relation_info;
- numIndices = resultRelationInfo->ri_NumIndices;
- relationDescs = resultRelationInfo->ri_IndexRelationDescs;
- indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
- heapRelation = resultRelationInfo->ri_RelationDesc;
+ resultRelInfo = estate->es_result_relation_info;
+ numIndices = resultRelInfo->ri_NumIndices;
+ relationDescs = resultRelInfo->ri_IndexRelationDescs;
+ indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
+ heapRelation = resultRelInfo->ri_RelationDesc;
heapDescriptor = RelationGetDescr(heapRelation);
/*
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index e5a5e55ef8d..ca9c48e294d 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.39 2000/10/26 21:35:15 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.40 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -253,7 +253,6 @@ init_sql_fcache(FmgrInfo *finfo)
slot->ttc_descIsNew = true;
slot->ttc_tupleDescriptor = (TupleDesc) NULL;
slot->ttc_buffer = InvalidBuffer;
- slot->ttc_whichplan = -1;
fcache->funcSlot = slot;
}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 81eeb1e8b0b..e47ec5756cb 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.37 2000/11/09 18:12:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.38 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,8 +36,8 @@
* nil nil ... ... ...
* subplans
*
- * Append nodes are currently used for unions, and to support inheritance
- * queries, where several relations need to be scanned.
+ * Append nodes are currently used for unions, and to support
+ * inheritance queries, where several relations need to be scanned.
* For example, in our standard person/student/employee/student-emp
* example, where student and employee inherit from person
* and student-emp inherits from student and employee, the
@@ -54,8 +54,8 @@
* | | | |
* person employee student student-emp
*/
-#include "postgres.h"
+#include "postgres.h"
#include "access/heapam.h"
#include "executor/execdebug.h"
@@ -78,12 +78,8 @@ exec_append_initialize_next(Append *node)
{
EState *estate;
AppendState *appendstate;
- TupleTableSlot *result_slot;
- List *rangeTable;
int whichplan;
int nplans;
- List *inheritrtable;
- RangeTblEntry *rtentry;
/* ----------------
* get information from the append node
@@ -91,12 +87,8 @@ exec_append_initialize_next(Append *node)
*/
estate = node->plan.state;
appendstate = node->appendstate;
- result_slot = appendstate->cstate.cs_ResultTupleSlot;
- rangeTable = estate->es_range_table;
-
whichplan = appendstate->as_whichplan;
nplans = appendstate->as_nplans;
- inheritrtable = node->inheritrtable;
if (whichplan < 0)
{
@@ -110,7 +102,6 @@ exec_append_initialize_next(Append *node)
*/
appendstate->as_whichplan = 0;
return FALSE;
-
}
else if (whichplan >= nplans)
{
@@ -121,37 +112,25 @@ exec_append_initialize_next(Append *node)
*/
appendstate->as_whichplan = nplans - 1;
return FALSE;
-
}
else
{
/* ----------------
* initialize the scan
- * (and update the range table appropriately)
*
- * (doesn't this leave the range table hosed for anybody upstream
- * of the Append node??? - jolly )
+ * If we are controlling the target relation, select the proper
+ * active ResultRelInfo and junk filter for this target.
* ----------------
*/
- if (node->inheritrelid > 0)
+ if (node->isTarget)
{
- rtentry = nth(whichplan, inheritrtable);
- Assert(rtentry != NULL);
- rt_store(node->inheritrelid, rangeTable, rtentry);
+ Assert(whichplan < estate->es_num_result_relations);
+ estate->es_result_relation_info =
+ estate->es_result_relations + whichplan;
+ estate->es_junkFilter =
+ estate->es_result_relation_info->ri_junkFilter;
}
- if (appendstate->as_junkFilter_list)
- {
- estate->es_junkFilter = (JunkFilter *) nth(whichplan,
- appendstate->as_junkFilter_list);
- }
- if (appendstate->as_result_relation_info_list)
- {
- estate->es_result_relation_info = (RelationInfo *) nth(whichplan,
- appendstate->as_result_relation_info_list);
- }
- result_slot->ttc_whichplan = whichplan;
-
return TRUE;
}
}
@@ -176,14 +155,10 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
{
AppendState *appendstate;
int nplans;
- List *inheritrtable;
List *appendplans;
bool *initialized;
int i;
Plan *initNode;
- List *junkList;
- RelationInfo *es_rri = estate->es_result_relation_info;
- bool inherited_result_rel = false;
CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
@@ -196,7 +171,6 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
appendplans = node->appendplans;
nplans = length(appendplans);
- inheritrtable = node->inheritrtable;
initialized = (bool *) palloc(nplans * sizeof(bool));
MemSet(initialized, 0, nplans * sizeof(bool));
@@ -228,119 +202,25 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
*/
ExecInitResultTupleSlot(estate, &appendstate->cstate);
- /*
- * If the inherits rtentry is the result relation, we have to make a
- * result relation info list for all inheritors so we can update their
- * indices and put the result tuples in the right place etc.
- *
- * e.g. replace p (age = p.age + 1) from p in person*
- */
- if ((es_rri != (RelationInfo *) NULL) &&
- (node->inheritrelid == es_rri->ri_RangeTableIndex))
- {
- List *resultList = NIL;
- Oid initial_reloid = RelationGetRelid(es_rri->ri_RelationDesc);
- List *rtentryP;
-
- inherited_result_rel = true;
-
- foreach(rtentryP, inheritrtable)
- {
- RangeTblEntry *rtentry = lfirst(rtentryP);
- Oid reloid = rtentry->relid;
- RelationInfo *rri;
-
- /*
- * We must recycle the RelationInfo already opened by InitPlan()
- * for the parent rel, else we will leak the associated relcache
- * refcount.
- */
- if (reloid == initial_reloid)
- {
- Assert(es_rri != NULL); /* check we didn't use it already */
- rri = es_rri;
- es_rri = NULL;
- }
- else
- {
- rri = makeNode(RelationInfo);
- rri->ri_RangeTableIndex = node->inheritrelid;
- rri->ri_RelationDesc = heap_open(reloid, RowExclusiveLock);
- rri->ri_NumIndices = 0;
- rri->ri_IndexRelationDescs = NULL; /* index descs */
- rri->ri_IndexRelationInfo = NULL; /* index key info */
-
- /*
- * XXX if the operation is a DELETE then we need not open
- * indices, but how to tell that here?
- */
- if (rri->ri_RelationDesc->rd_rel->relhasindex)
- ExecOpenIndices(rri);
- }
-
- /*
- * NB: the as_result_relation_info_list must be in the same
- * order as the rtentry list otherwise update or delete on
- * inheritance hierarchies won't work.
- */
- resultList = lappend(resultList, rri);
- }
-
- appendstate->as_result_relation_info_list = resultList;
- /* Check that we recycled InitPlan()'s RelationInfo */
- Assert(es_rri == NULL);
- /* Just for paranoia's sake, clear link until we set it properly */
- estate->es_result_relation_info = NULL;
- }
-
/* ----------------
* call ExecInitNode on each of the plans in our list
* and save the results into the array "initialized"
* ----------------
*/
- junkList = NIL;
-
for (i = 0; i < nplans; i++)
{
- /* ----------------
- * NOTE: we first modify range table in
- * exec_append_initialize_next() and
- * then initialize the subnode,
- * since it may use the range table.
- * ----------------
- */
appendstate->as_whichplan = i;
exec_append_initialize_next(node);
initNode = (Plan *) nth(i, appendplans);
initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
-
- /* ---------------
- * Each targetlist in the subplan may need its own junk filter
- *
- * This is true only when the reln being replaced/deleted is
- * the one that we're looking at the subclasses of
- * ---------------
- */
- if (inherited_result_rel)
- {
- JunkFilter *j = ExecInitJunkFilter(initNode->targetlist,
- ExecGetTupType(initNode));
-
- junkList = lappend(junkList, j);
- }
-
}
- appendstate->as_junkFilter_list = junkList;
- if (junkList != NIL)
- estate->es_junkFilter = (JunkFilter *) lfirst(junkList);
/* ----------------
- * initialize the return type from the appropriate subplan.
+ * initialize tuple type
* ----------------
*/
- initNode = (Plan *) nth(0, appendplans);
- ExecAssignResultType(&appendstate->cstate, ExecGetTupType(initNode));
+ ExecAssignResultTypeFromTL((Plan *) node, &appendstate->cstate);
appendstate->cstate.cs_ProjInfo = NULL;
/* ----------------
@@ -357,10 +237,9 @@ int
ExecCountSlotsAppend(Append *node)
{
List *plan;
- List *appendplans = node->appendplans;
int nSlots = 0;
- foreach(plan, appendplans)
+ foreach(plan, node->appendplans)
nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
return nSlots + APPEND_NSLOTS;
}
@@ -430,16 +309,14 @@ ExecProcAppend(Append *node)
* direction and try processing again (recursively)
* ----------------
*/
- whichplan = appendstate->as_whichplan;
-
if (ScanDirectionIsForward(direction))
- appendstate->as_whichplan = whichplan + 1;
+ appendstate->as_whichplan++;
else
- appendstate->as_whichplan = whichplan - 1;
+ appendstate->as_whichplan--;
/* ----------------
* return something from next node or an empty slot
- * all of our subplans have been exhausted.
+ * if all of our subplans have been exhausted.
* ----------------
*/
if (exec_append_initialize_next(node))
@@ -469,7 +346,6 @@ ExecEndAppend(Append *node)
List *appendplans;
bool *initialized;
int i;
- List *resultRelationInfoList;
/* ----------------
* get information from the node
@@ -490,40 +366,8 @@ ExecEndAppend(Append *node)
if (initialized[i])
ExecEndNode((Plan *) nth(i, appendplans), (Plan *) node);
}
-
- /* ----------------
- * close out the different result relations
- *
- * NB: this must agree with what EndPlan() does to close a result rel
- * ----------------
- */
- resultRelationInfoList = appendstate->as_result_relation_info_list;
- while (resultRelationInfoList != NIL)
- {
- RelationInfo *resultRelationInfo;
-
- resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
-
- heap_close(resultRelationInfo->ri_RelationDesc, NoLock);
- /* close indices on the result relation, too */
- ExecCloseIndices(resultRelationInfo);
-
- /*
- * estate may (or may not) be pointing at one of my result relations.
- * If so, make sure EndPlan() doesn't try to close it again!
- */
- if (estate->es_result_relation_info == resultRelationInfo)
- estate->es_result_relation_info = NULL;
-
- pfree(resultRelationInfo);
- resultRelationInfoList = lnext(resultRelationInfoList);
- }
- appendstate->as_result_relation_info_list = NIL;
-
- /*
- * XXX should free appendstate->as_junkfilter_list here
- */
}
+
void
ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
{
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index b953dcd3697..56ba1375feb 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.24 2000/07/12 02:37:04 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.25 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -156,7 +156,6 @@ InitScanRelation(SeqScan *node, EState *estate,
ScanDirection direction;
Relation currentRelation;
HeapScanDesc currentScanDesc;
- RelationInfo *resultRelationInfo;
/* ----------------
* get the relation object id from the relid'th entry
@@ -169,7 +168,6 @@ InitScanRelation(SeqScan *node, EState *estate,
rtentry = rt_fetch(relid, rangeTable);
reloid = rtentry->relid;
direction = estate->es_direction;
- resultRelationInfo = estate->es_result_relation_info;
ExecOpenScanR(reloid, /* relation */
0, /* nkeys */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 93866787f37..3490ef80624 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.130 2000/11/05 22:50:19 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.131 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -176,8 +176,7 @@ _copyAppend(Append *from)
* ----------------
*/
Node_Copy(from, newnode, appendplans);
- newnode->inheritrelid = from->inheritrelid;
- Node_Copy(from, newnode, inheritrtable);
+ newnode->isTarget = from->isTarget;
return newnode;
}
@@ -1276,6 +1275,30 @@ _copyTidPath(TidPath *from)
}
/* ----------------
+ * _copyAppendPath
+ * ----------------
+ */
+static AppendPath *
+_copyAppendPath(AppendPath *from)
+{
+ AppendPath *newnode = makeNode(AppendPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path *) from, (Path *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, subpaths);
+
+ return newnode;
+}
+
+/* ----------------
* CopyJoinPathFields
*
* This function copies the fields of the JoinPath node. It is used by
@@ -1767,6 +1790,8 @@ _copyQuery(Query *from)
Node_Copy(from, newnode, setOperations);
+ newnode->resultRelations = listCopy(from->resultRelations);
+
/*
* We do not copy the planner internal fields: base_rel_list,
* join_rel_list, equi_key_list, query_pathkeys. Not entirely clear if
@@ -2677,6 +2702,9 @@ copyObject(void *from)
case T_TidPath:
retval = _copyTidPath(from);
break;
+ case T_AppendPath:
+ retval = _copyAppendPath(from);
+ break;
case T_NestPath:
retval = _copyNestPath(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7ed95db9679..8fb81a45c0b 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.80 2000/11/05 22:50:19 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.81 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -436,6 +436,16 @@ _equalTidPath(TidPath *a, TidPath *b)
}
static bool
+_equalAppendPath(AppendPath *a, AppendPath *b)
+{
+ if (!_equalPath((Path *) a, (Path *) b))
+ return false;
+ if (!equal(a->subpaths, b->subpaths))
+ return false;
+ return true;
+}
+
+static bool
_equalJoinPath(JoinPath *a, JoinPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
@@ -556,28 +566,6 @@ _equalStream(Stream *a, Stream *b)
}
/*
- * Stuff from execnodes.h
- */
-
-/*
- * EState is a subclass of Node.
- */
-static bool
-_equalEState(EState *a, EState *b)
-{
- if (a->es_direction != b->es_direction)
- return false;
-
- if (!equal(a->es_range_table, b->es_range_table))
- return false;
-
- if (a->es_result_relation_info != b->es_result_relation_info)
- return false;
-
- return true;
-}
-
-/*
* Stuff from parsenodes.h
*/
@@ -624,6 +612,8 @@ _equalQuery(Query *a, Query *b)
return false;
if (!equal(a->setOperations, b->setOperations))
return false;
+ if (!equali(a->resultRelations, b->resultRelations))
+ return false;
/*
* We do not check the internal-to-the-planner fields: base_rel_list,
@@ -1851,14 +1841,13 @@ equal(void *a, void *b)
case T_TidPath:
retval = _equalTidPath(a, b);
break;
+ case T_AppendPath:
+ retval = _equalAppendPath(a, b);
+ break;
case T_IndexOptInfo:
retval = _equalIndexOptInfo(a, b);
break;
- case T_EState:
- retval = _equalEState(a, b);
- break;
-
case T_List:
{
List *la = (List *) a;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 58ab6896889..d7137f10ace 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.131 2000/10/31 13:59:52 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.132 2000/11/12 00:36:57 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -296,6 +296,9 @@ _outQuery(StringInfo str, Query *node)
appendStringInfo(str, " :setOperations ");
_outNode(str, node->setOperations);
+
+ appendStringInfo(str, " :resultRelations ");
+ _outIntList(str, node->resultRelations);
}
static void
@@ -327,17 +330,18 @@ _outSetOperationStmt(StringInfo str, SetOperationStmt *node)
/*
* print the basic stuff of all nodes that inherit from Plan
+ *
+ * NOTE: we deliberately omit the execution state (EState)
*/
static void
_outPlanInfo(StringInfo str, Plan *node)
{
appendStringInfo(str,
- ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
+ ":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :qptargetlist ",
node->startup_cost,
node->total_cost,
node->plan_rows,
- node->plan_width,
- node->state ? "not-NULL" : "<>");
+ node->plan_width);
_outNode(str, node->targetlist);
appendStringInfo(str, " :qpqual ");
@@ -394,9 +398,8 @@ _outAppend(StringInfo str, Append *node)
appendStringInfo(str, " :appendplans ");
_outNode(str, node->appendplans);
- appendStringInfo(str, " :inheritrelid %u :inheritrtable ",
- node->inheritrelid);
- _outNode(str, node->inheritrtable);
+ appendStringInfo(str, " :isTarget %s ",
+ node->isTarget ? "true" : "false");
}
/*
@@ -946,25 +949,6 @@ _outJoinExpr(StringInfo str, JoinExpr *node)
}
/*
- * Stuff from execnodes.h
- */
-
-/*
- * EState is a subclass of Node.
- */
-static void
-_outEState(StringInfo str, EState *node)
-{
- appendStringInfo(str,
- " ESTATE :direction %d :range_table ",
- node->es_direction);
- _outNode(str, node->es_range_table);
-
- appendStringInfo(str, " :result_relation_info @ 0x%x ",
- (int) (node->es_result_relation_info));
-}
-
-/*
* Stuff from relation.h
*/
@@ -1107,11 +1091,28 @@ _outTidPath(StringInfo str, TidPath *node)
appendStringInfo(str, " :tideval ");
_outNode(str, node->tideval);
- appendStringInfo(str, " :un joined_relids ");
+ appendStringInfo(str, " :unjoined_relids ");
_outIntList(str, node->unjoined_relids);
}
/*
+ * AppendPath is a subclass of Path.
+ */
+static void
+_outAppendPath(StringInfo str, AppendPath *node)
+{
+ appendStringInfo(str,
+ " APPENDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
+ node->path.pathtype,
+ node->path.startup_cost,
+ node->path.total_cost);
+ _outNode(str, node->path.pathkeys);
+
+ appendStringInfo(str, " :subpaths ");
+ _outNode(str, node->subpaths);
+}
+
+/*
* NestPath is a subclass of Path
*/
static void
@@ -1632,9 +1633,6 @@ _outNode(StringInfo str, void *obj)
case T_JoinExpr:
_outJoinExpr(str, obj);
break;
- case T_EState:
- _outEState(str, obj);
- break;
case T_RelOptInfo:
_outRelOptInfo(str, obj);
break;
@@ -1656,6 +1654,9 @@ _outNode(StringInfo str, void *obj)
case T_TidPath:
_outTidPath(str, obj);
break;
+ case T_AppendPath:
+ _outAppendPath(str, obj);
+ break;
case T_NestPath:
_outNestPath(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 354ac8d5839..6a6dce48bfb 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.99 2000/10/22 22:14:54 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.100 2000/11/12 00:36:57 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@@ -150,6 +150,9 @@ _readQuery(void)
token = lsptok(NULL, &length); /* skip :setOperations */
local_node->setOperations = nodeRead(true);
+ token = lsptok(NULL, &length); /* skip :resultRelations */
+ local_node->resultRelations = toIntList(nodeRead(true));
+
return local_node;
}
@@ -260,17 +263,6 @@ _getPlan(Plan *node)
token = lsptok(NULL, &length); /* get the plan_width */
node->plan_width = atoi(token);
- token = lsptok(NULL, &length); /* eat the :state stuff */
- token = lsptok(NULL, &length); /* now get the state */
-
- if (length == 0)
- node->state = (EState *) NULL;
- else
- { /* Disgusting hack until I figure out what
- * to do here */
- node->state = (EState *) !NULL;
- }
-
token = lsptok(NULL, &length); /* eat :qptargetlist */
node->targetlist = nodeRead(true);
@@ -283,6 +275,8 @@ _getPlan(Plan *node)
token = lsptok(NULL, &length); /* eat :righttree */
node->righttree = (Plan *) nodeRead(true);
+ node->state = (EState *) NULL; /* never read in */
+
return;
}
@@ -348,12 +342,9 @@ _readAppend(void)
token = lsptok(NULL, &length); /* eat :appendplans */
local_node->appendplans = nodeRead(true); /* now read it */
- token = lsptok(NULL, &length); /* eat :inheritrelid */
- token = lsptok(NULL, &length); /* get inheritrelid */
- local_node->inheritrelid = strtoul(token, NULL, 10);
-
- token = lsptok(NULL, &length); /* eat :inheritrtable */
- local_node->inheritrtable = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* eat :isTarget */
+ token = lsptok(NULL, &length); /* get isTarget */
+ local_node->isTarget = (token[0] == 't') ? true : false;
return local_node;
}
@@ -1298,43 +1289,6 @@ _readJoinExpr(void)
}
/*
- * Stuff from execnodes.h
- */
-
-/* ----------------
- * _readEState
- *
- * EState is a subclass of Node.
- * ----------------
- */
-static EState *
-_readEState(void)
-{
- EState *local_node;
- char *token;
- int length;
-
- local_node = makeNode(EState);
-
- token = lsptok(NULL, &length); /* get :direction */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->es_direction = atoi(token);
-
- token = lsptok(NULL, &length); /* get :range_table */
-
- local_node->es_range_table = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :result_relation_info */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- sscanf(token, "%x", (unsigned int *) &local_node->es_result_relation_info);
-
- return local_node;
-}
-
-/*
* Stuff from relation.h
*/
@@ -1640,6 +1594,42 @@ _readTidPath(void)
}
/* ----------------
+ * _readAppendPath
+ *
+ * AppendPath is a subclass of Path.
+ * ----------------
+ */
+static AppendPath *
+_readAppendPath(void)
+{
+ AppendPath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(AppendPath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :startup_cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.startup_cost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :total_cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.total_cost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :pathkeys */
+ local_node->path.pathkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :subpaths */
+ local_node->subpaths = nodeRead(true); /* now read it */
+
+ return local_node;
+}
+
+/* ----------------
* _readNestPath
*
* NestPath is a subclass of Path
@@ -1984,8 +1974,6 @@ parsePlanString(void)
return_value = _readOper();
else if (length == 5 && strncmp(token, "PARAM", length) == 0)
return_value = _readParam();
- else if (length == 6 && strncmp(token, "ESTATE", length) == 0)
- return_value = _readEState();
else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
return_value = _readRelOptInfo();
else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
@@ -1998,6 +1986,8 @@ parsePlanString(void)
return_value = _readIndexPath();
else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
return_value = _readTidPath();
+ else if (length == 10 && strncmp(token, "APPENDPATH", length) == 0)
+ return_value = _readAppendPath();
else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
return_value = _readNestPath();
else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)
diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README
index f0113dfaf50..e60f1457208 100644
--- a/src/backend/optimizer/README
+++ b/src/backend/optimizer/README
@@ -4,11 +4,11 @@ Summary
These directories take the Query structure returned by the parser, and
generate a plan used by the executor. The /plan directory generates the
actual output plan, the /path code generates all possible ways to join the
-tables, and /prep handles special cases like inheritance. /util is utility
-stuff. /geqo is the separate "genetic optimization" planner --- it does
-a semi-random search through the join tree space, rather than exhaustively
-considering all possible join trees. (But each join considered by /geqo
-is given to /path to create paths for, so we consider all possible
+tables, and /prep handles various preprocessing steps for special cases.
+/util is utility stuff. /geqo is the separate "genetic optimization" planner
+--- it does a semi-random search through the join tree space, rather than
+exhaustively considering all possible join trees. (But each join considered
+by /geqo is given to /path to create paths for, so we consider all possible
implementation paths for each specific join pair even in GEQO mode.)
@@ -210,10 +210,10 @@ planner()
thereby reducing the accuracy of selectivity estimates.
process sublinks
convert Vars of outer query levels into Params
---union_planner()
- handle unions and inheritance by mutual recursion with prepunion.c routines
- preprocess target list
- handle GROUP BY, HAVING, aggregates, ORDER BY, DISTINCT
+--grouping_planner()
+ preprocess target list for non-SELECT queries
+ handle UNION/INTERSECT/EXCEPT, GROUP BY, HAVING, aggregates,
+ ORDER BY, DISTINCT, LIMIT
--query_planner()
pull out constant quals, which can be used to gate execution of the
whole plan (if any are found, we make a top-level Result node
@@ -239,11 +239,12 @@ planner()
Loop back if this wasn't the top join level.
Back at query_planner:
put back constant quals and non-simplified target list
- Back at union_planner:
+ Back at grouping_planner:
do grouping(GROUP)
do aggregates
make unique(DISTINCT)
make sort(ORDER BY)
+ make limit(LIMIT/OFFSET)
Optimizer Data Structures
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 7e017a746f1..12fc576612f 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.66 2000/10/05 19:11:28 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.67 2000/11/12 00:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/planner.h"
+#include "optimizer/prep.h"
#include "parser/parsetree.h"
@@ -28,7 +29,12 @@ bool enable_geqo = true;
int geqo_rels = DEFAULT_GEQO_RELS;
-static void set_base_rel_pathlist(Query *root);
+static void set_base_rel_pathlists(Query *root);
+static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel,
+ RangeTblEntry *rte);
+static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
+ RangeTblEntry *rte,
+ List *inheritlist);
static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
List *initial_rels);
@@ -51,7 +57,7 @@ make_one_rel(Query *root)
/*
* Generate access paths for the base rels.
*/
- set_base_rel_pathlist(root);
+ set_base_rel_pathlists(root);
/*
* Generate access paths for the entire join tree.
@@ -69,23 +75,26 @@ make_one_rel(Query *root)
}
/*
- * set_base_rel_pathlist
+ * set_base_rel_pathlists
* Finds all paths available for scanning each base-relation entry.
* Sequential scan and any available indices are considered.
* Each useful path is attached to its relation's 'pathlist' field.
*/
static void
-set_base_rel_pathlist(Query *root)
+set_base_rel_pathlists(Query *root)
{
List *rellist;
foreach(rellist, root->base_rel_list)
{
RelOptInfo *rel = (RelOptInfo *) lfirst(rellist);
+ Index rti;
RangeTblEntry *rte;
+ List *inheritlist;
Assert(length(rel->relids) == 1); /* better be base rel */
- rte = rt_fetch(lfirsti(rel->relids), root->rtable);
+ rti = lfirsti(rel->relids);
+ rte = rt_fetch(rti, root->rtable);
if (rel->issubquery)
{
@@ -109,47 +118,163 @@ set_base_rel_pathlist(Query *root)
/* Generate appropriate path */
add_path(rel, create_subqueryscan_path(rel));
+
+ /* Select cheapest path (pretty easy in this case...) */
+ set_cheapest(rel);
+ }
+ else if ((inheritlist = expand_inherted_rtentry(root, rti)) != NIL)
+ {
+ /* Relation is root of an inheritance tree, process specially */
+ set_inherited_rel_pathlist(root, rel, rte, inheritlist);
}
else
{
/* Plain relation */
- List *indices = find_secondary_indexes(rte->relid);
+ set_plain_rel_pathlist(root, rel, rte);
+ }
+ }
+}
- /* Mark rel with estimated output rows, width, etc */
- set_baserel_size_estimates(root, rel);
+/*
+ * set_plain_rel_pathlist
+ * Build access paths for a plain relation (no subquery, no inheritance)
+ */
+static void
+set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
+{
+ List *indices = find_secondary_indexes(rte->relid);
- /*
- * Generate paths and add them to the rel's pathlist.
- *
- * Note: add_path() will discard any paths that are dominated by
- * another available path, keeping only those paths that are
- * superior along at least one dimension of cost or sortedness.
- */
+ /* Mark rel with estimated output rows, width, etc */
+ set_baserel_size_estimates(root, rel);
- /* Consider sequential scan */
- add_path(rel, create_seqscan_path(rel));
+ /*
+ * Generate paths and add them to the rel's pathlist.
+ *
+ * Note: add_path() will discard any paths that are dominated by
+ * another available path, keeping only those paths that are
+ * superior along at least one dimension of cost or sortedness.
+ */
- /* Consider TID scans */
- create_tidscan_paths(root, rel);
+ /* Consider sequential scan */
+ add_path(rel, create_seqscan_path(rel));
- /* Consider index paths for both simple and OR index clauses */
- create_index_paths(root, rel, indices,
- rel->baserestrictinfo,
- rel->joininfo);
+ /* Consider TID scans */
+ create_tidscan_paths(root, rel);
- /*
- * Note: create_or_index_paths depends on create_index_paths to
- * have marked OR restriction clauses with relevant indices; this
- * is why it doesn't need to be given the list of indices.
- */
- create_or_index_paths(root, rel, rel->baserestrictinfo);
- }
+ /* Consider index paths for both simple and OR index clauses */
+ create_index_paths(root, rel, indices,
+ rel->baserestrictinfo,
+ rel->joininfo);
+
+ /*
+ * Note: create_or_index_paths depends on create_index_paths to
+ * have marked OR restriction clauses with relevant indices; this
+ * is why it doesn't need to be given the list of indices.
+ */
+ create_or_index_paths(root, rel, rel->baserestrictinfo);
+
+ /* Now find the cheapest of the paths for this rel */
+ set_cheapest(rel);
+}
+
+/*
+ * set_inherited_rel_pathlist
+ * Build access paths for a inheritance tree rooted at rel
+ *
+ * inheritlist is a list of RT indexes of all tables in the inheritance tree,
+ * including the parent itself. Note we will not come here unless there's
+ * at least one child in addition to the parent.
+ */
+static void
+set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
+ List *inheritlist)
+{
+ int parentRTindex = lfirsti(rel->relids);
+ Oid parentOID = rte->relid;
+ List *subpaths = NIL;
+ List *il;
+
+ /*
+ * XXX for now, can't handle inherited expansion of FOR UPDATE;
+ * can we do better?
+ */
+ if (intMember(parentRTindex, root->rowMarks))
+ elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries");
- /* Now find the cheapest of the paths for this rel */
- set_cheapest(rel);
+ /*
+ * Recompute size estimates for whole inheritance tree
+ */
+ rel->rows = 0;
+ rel->width = 0;
+
+ /*
+ * Generate access paths for each table in the tree (parent AND children),
+ * and pick the cheapest path for each table.
+ */
+ foreach(il, inheritlist)
+ {
+ int childRTindex = lfirsti(il);
+ RangeTblEntry *childrte;
+ Oid childOID;
+ RelOptInfo *childrel;
+
+ childrte = rt_fetch(childRTindex, root->rtable);
+ childOID = childrte->relid;
+
+ /*
+ * Make a RelOptInfo for the child so we can do planning. Do NOT
+ * attach the RelOptInfo to the query's base_rel_list, however.
+ *
+ * NOTE: when childRTindex == parentRTindex, we create a second
+ * RelOptInfo for the same relation. This RelOptInfo will represent
+ * the parent table alone, whereas the original RelOptInfo represents
+ * the union of the inheritance tree members.
+ */
+ childrel = make_base_rel(root, childRTindex);
+
+ /*
+ * Copy the parent's targetlist and restriction quals to the child,
+ * with attribute-number adjustment if needed. We don't bother
+ * to copy the join quals, since we can't do any joining here.
+ */
+ childrel->targetlist = (List *)
+ adjust_inherited_attrs((Node *) rel->targetlist,
+ parentRTindex,
+ parentOID,
+ childRTindex,
+ childOID);
+ childrel->baserestrictinfo = (List *)
+ adjust_inherited_attrs((Node *) rel->baserestrictinfo,
+ parentRTindex,
+ parentOID,
+ childRTindex,
+ childOID);
+ childrel->baserestrictcost = rel->baserestrictcost;
+
+ /*
+ * Now compute child access paths, and save the cheapest.
+ */
+ set_plain_rel_pathlist(root, childrel, childrte);
+
+ subpaths = lappend(subpaths, childrel->cheapest_total_path);
+
+ /* Also update total size estimates */
+ rel->rows += childrel->rows;
+ if (childrel->width > rel->width)
+ rel->width = childrel->width;
}
+
+ /*
+ * Finally, build Append path and install it as the only access
+ * path for the parent rel.
+ */
+ add_path(rel, (Path *) create_append_path(rel, subpaths));
+
+ /* Select cheapest path (pretty easy in this case...) */
+ set_cheapest(rel);
}
+
/*
* make_fromexpr_rel
* Build access paths for a FromExpr jointree node.
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 820492bd186..f94d2e4037b 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.26 2000/09/29 18:21:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.27 2000/11/12 00:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -566,8 +566,8 @@ build_join_pathkeys(List *outer_pathkeys,
* NB: the result is NOT in canonical form, but must be passed through
* canonicalize_pathkeys() before it can be used for comparisons or
* labeling relation sort orders. (We do things this way because
- * union_planner needs to be able to construct requested pathkeys before
- * the pathkey equivalence sets have been created for the query.)
+ * grouping_planner needs to be able to construct requested pathkeys
+ * before the pathkey equivalence sets have been created for the query.)
*
* 'sortclauses' is a list of SortClause or GroupClause nodes
* 'tlist' is the targetlist to find the referenced tlist entries in
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index a865da61b92..4069ed66e58 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.99 2000/10/26 21:36:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.100 2000/11/12 00:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,35 +32,38 @@
#include "utils/syscache.h"
-static List *switch_outer(List *clauses);
-static Scan *create_scan_node(Query *root, Path *best_path, List *tlist);
-static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist);
-static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
+static Scan *create_scan_plan(Query *root, Path *best_path);
+static Join *create_join_plan(Query *root, JoinPath *best_path);
+static Append *create_append_plan(Query *root, AppendPath *best_path);
+static SeqScan *create_seqscan_plan(Path *best_path, List *tlist,
List *scan_clauses);
-static IndexScan *create_indexscan_node(Query *root, IndexPath *best_path,
+static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
List *tlist, List *scan_clauses);
-static TidScan *create_tidscan_node(TidPath *best_path, List *tlist,
+static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist,
List *scan_clauses);
-static SubqueryScan *create_subqueryscan_node(Path *best_path,
+static SubqueryScan *create_subqueryscan_plan(Path *best_path,
List *tlist, List *scan_clauses);
-static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
+static NestLoop *create_nestloop_plan(NestPath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
- Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
+ Plan *outer_plan, List *outer_tlist,
+ Plan *inner_plan, List *inner_tlist);
+static MergeJoin *create_mergejoin_plan(MergePath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
- Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
+ Plan *outer_plan, List *outer_tlist,
+ Plan *inner_plan, List *inner_tlist);
+static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
- Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
+ Plan *outer_plan, List *outer_tlist,
+ Plan *inner_plan, List *inner_tlist);
static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
Form_pg_index index);
static Node *fix_indxqual_operand(Node *node, int baserelid,
Form_pg_index index,
Oid *opclass);
+static List *switch_outer(List *clauses);
+static void copy_path_costsize(Plan *dest, Path *src);
+static void copy_plan_costsize(Plan *dest, Plan *src);
static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
List *indxid, List *indxqual,
@@ -83,7 +86,6 @@ static MergeJoin *make_mergejoin(List *tlist,
List *mergeclauses,
Plan *lefttree, Plan *righttree,
JoinType jointype);
-static void copy_path_costsize(Plan *dest, Path *src);
/*
* create_plan
@@ -98,13 +100,12 @@ static void copy_path_costsize(Plan *dest, Path *src);
*
* best_path is the best access path
*
- * Returns the access plan.
+ * Returns a Plan tree.
*/
Plan *
create_plan(Query *root, Path *best_path)
{
- List *tlist = best_path->parent->targetlist;
- Plan *plan_node = (Plan *) NULL;
+ Plan *plan;
switch (best_path->pathtype)
{
@@ -112,18 +113,22 @@ create_plan(Query *root, Path *best_path)
case T_SeqScan:
case T_TidScan:
case T_SubqueryScan:
- plan_node = (Plan *) create_scan_node(root, best_path, tlist);
+ plan = (Plan *) create_scan_plan(root, best_path);
break;
case T_HashJoin:
case T_MergeJoin:
case T_NestLoop:
- plan_node = (Plan *) create_join_node(root,
- (JoinPath *) best_path,
- tlist);
+ plan = (Plan *) create_join_plan(root,
+ (JoinPath *) best_path);
+ break;
+ case T_Append:
+ plan = (Plan *) create_append_plan(root,
+ (AppendPath *) best_path);
break;
default:
elog(ERROR, "create_plan: unknown pathtype %d",
best_path->pathtype);
+ plan = NULL; /* keep compiler quiet */
break;
}
@@ -131,30 +136,29 @@ create_plan(Query *root, Path *best_path)
/* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
if (XfuncMode != XFUNC_OFF)
{
- set_qpqual((Plan) plan_node,
- lisp_qsort(get_qpqual((Plan) plan_node),
+ set_qpqual((Plan) plan,
+ lisp_qsort(get_qpqual((Plan) plan),
xfunc_clause_compare));
if (XfuncMode != XFUNC_NOR)
/* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
- xfunc_disjunct_sort(plan_node->qpqual);
+ xfunc_disjunct_sort(plan->qpqual);
}
#endif
- return plan_node;
+ return plan;
}
/*
- * create_scan_node
- * Create a scan path for the parent relation of 'best_path'.
+ * create_scan_plan
+ * Create a scan plan for the parent relation of 'best_path'.
*
- * tlist is the targetlist for the base relation scanned by 'best_path'
- *
- * Returns the scan node.
+ * Returns a Plan node.
*/
static Scan *
-create_scan_node(Query *root, Path *best_path, List *tlist)
+create_scan_plan(Query *root, Path *best_path)
{
- Scan *node = NULL;
+ Scan *plan;
+ List *tlist = best_path->parent->targetlist;
List *scan_clauses;
/*
@@ -166,65 +170,64 @@ create_scan_node(Query *root, Path *best_path, List *tlist)
switch (best_path->pathtype)
{
case T_SeqScan:
- node = (Scan *) create_seqscan_node(best_path,
+ plan = (Scan *) create_seqscan_plan(best_path,
tlist,
scan_clauses);
break;
case T_IndexScan:
- node = (Scan *) create_indexscan_node(root,
+ plan = (Scan *) create_indexscan_plan(root,
(IndexPath *) best_path,
tlist,
scan_clauses);
break;
case T_TidScan:
- node = (Scan *) create_tidscan_node((TidPath *) best_path,
+ plan = (Scan *) create_tidscan_plan((TidPath *) best_path,
tlist,
scan_clauses);
break;
case T_SubqueryScan:
- node = (Scan *) create_subqueryscan_node(best_path,
+ plan = (Scan *) create_subqueryscan_plan(best_path,
tlist,
scan_clauses);
break;
default:
- elog(ERROR, "create_scan_node: unknown node type: %d",
+ elog(ERROR, "create_scan_plan: unknown node type: %d",
best_path->pathtype);
+ plan = NULL; /* keep compiler quiet */
break;
}
- return node;
+ return plan;
}
/*
- * create_join_node
- * Create a join path for 'best_path' and(recursively) paths for its
+ * create_join_plan
+ * Create a join plan for 'best_path' and (recursively) plans for its
* inner and outer paths.
*
- * 'tlist' is the targetlist for the join relation corresponding to
- * 'best_path'
- *
- * Returns the join node.
+ * Returns a Plan node.
*/
static Join *
-create_join_node(Query *root, JoinPath *best_path, List *tlist)
+create_join_plan(Query *root, JoinPath *best_path)
{
- Plan *outer_node;
+ List *join_tlist = best_path->path.parent->targetlist;
+ Plan *outer_plan;
List *outer_tlist;
- Plan *inner_node;
+ Plan *inner_plan;
List *inner_tlist;
List *joinclauses;
List *otherclauses;
- Join *retval = NULL;
+ Join *plan;
- outer_node = create_plan(root, best_path->outerjoinpath);
- outer_tlist = outer_node->targetlist;
+ outer_plan = create_plan(root, best_path->outerjoinpath);
+ outer_tlist = outer_plan->targetlist;
- inner_node = create_plan(root, best_path->innerjoinpath);
- inner_tlist = inner_node->targetlist;
+ inner_plan = create_plan(root, best_path->innerjoinpath);
+ inner_tlist = inner_plan->targetlist;
if (IS_OUTER_JOIN(best_path->jointype))
{
@@ -241,38 +244,40 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist)
switch (best_path->path.pathtype)
{
case T_MergeJoin:
- retval = (Join *) create_mergejoin_node((MergePath *) best_path,
- tlist,
- joinclauses,
- otherclauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
+ plan = (Join *) create_mergejoin_plan((MergePath *) best_path,
+ join_tlist,
+ joinclauses,
+ otherclauses,
+ outer_plan,
+ outer_tlist,
+ inner_plan,
+ inner_tlist);
break;
case T_HashJoin:
- retval = (Join *) create_hashjoin_node((HashPath *) best_path,
- tlist,
- joinclauses,
- otherclauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
+ plan = (Join *) create_hashjoin_plan((HashPath *) best_path,
+ join_tlist,
+ joinclauses,
+ otherclauses,
+ outer_plan,
+ outer_tlist,
+ inner_plan,
+ inner_tlist);
break;
case T_NestLoop:
- retval = (Join *) create_nestloop_node((NestPath *) best_path,
- tlist,
- joinclauses,
- otherclauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
+ plan = (Join *) create_nestloop_plan((NestPath *) best_path,
+ join_tlist,
+ joinclauses,
+ otherclauses,
+ outer_plan,
+ outer_tlist,
+ inner_plan,
+ inner_tlist);
break;
default:
- elog(ERROR, "create_join_node: unknown node type: %d",
+ elog(ERROR, "create_join_plan: unknown node type: %d",
best_path->path.pathtype);
+ plan = NULL; /* keep compiler quiet */
+ break;
}
#ifdef NOT_USED
@@ -283,14 +288,42 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist)
* JMH, 6/15/92
*/
if (get_loc_restrictinfo(best_path) != NIL)
- set_qpqual((Plan) retval,
- nconc(get_qpqual((Plan) retval),
+ set_qpqual((Plan) plan,
+ nconc(get_qpqual((Plan) plan),
get_actual_clauses(get_loc_restrictinfo(best_path))));
#endif
- return retval;
+ return plan;
}
+/*
+ * create_append_plan
+ * Create an Append plan for 'best_path' and (recursively) plans
+ * for its subpaths.
+ *
+ * Returns a Plan node.
+ */
+static Append *
+create_append_plan(Query *root, AppendPath *best_path)
+{
+ Append *plan;
+ List *tlist = best_path->path.parent->targetlist;
+ List *subplans = NIL;
+ List *subpaths;
+
+ foreach(subpaths, best_path->subpaths)
+ {
+ Path *subpath = (Path *) lfirst(subpaths);
+
+ subplans = lappend(subplans, create_plan(root, subpath));
+ }
+
+ plan = make_append(subplans, false, tlist);
+
+ return plan;
+}
+
+
/*****************************************************************************
*
* BASE-RELATION SCAN METHODS
@@ -299,14 +332,14 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist)
/*
- * create_seqscan_node
- * Returns a seqscan node for the base relation scanned by 'best_path'
+ * create_seqscan_plan
+ * Returns a seqscan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static SeqScan *
-create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
+create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
{
- SeqScan *scan_node;
+ SeqScan *scan_plan;
Index scan_relid;
/* there should be exactly one base rel involved... */
@@ -315,18 +348,18 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
scan_relid = (Index) lfirsti(best_path->parent->relids);
- scan_node = make_seqscan(tlist,
+ scan_plan = make_seqscan(tlist,
scan_clauses,
scan_relid);
- copy_path_costsize(&scan_node->plan, best_path);
+ copy_path_costsize(&scan_plan->plan, best_path);
- return scan_node;
+ return scan_plan;
}
/*
- * create_indexscan_node
- * Returns a indexscan node for the base relation scanned by 'best_path'
+ * create_indexscan_plan
+ * Returns a indexscan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*
* The indexqual of the path contains a sublist of implicitly-ANDed qual
@@ -338,7 +371,7 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
* scan.
*/
static IndexScan *
-create_indexscan_node(Query *root,
+create_indexscan_plan(Query *root,
IndexPath *best_path,
List *tlist,
List *scan_clauses)
@@ -348,7 +381,7 @@ create_indexscan_node(Query *root,
List *qpqual;
List *fixed_indxqual;
List *ixid;
- IndexScan *scan_node;
+ IndexScan *scan_plan;
bool lossy = false;
/* there should be exactly one base rel involved... */
@@ -433,7 +466,7 @@ create_indexscan_node(Query *root,
*/
fixed_indxqual = fix_indxqual_references(indxqual, best_path);
- scan_node = make_indexscan(tlist,
+ scan_plan = make_indexscan(tlist,
qpqual,
baserelid,
best_path->indexid,
@@ -441,22 +474,22 @@ create_indexscan_node(Query *root,
indxqual,
best_path->indexscandir);
- copy_path_costsize(&scan_node->scan.plan, &best_path->path);
+ copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
/* use the indexscan-specific rows estimate, not the parent rel's */
- scan_node->scan.plan.plan_rows = best_path->rows;
+ scan_plan->scan.plan.plan_rows = best_path->rows;
- return scan_node;
+ return scan_plan;
}
/*
- * create_tidscan_node
- * Returns a tidscan node for the base relation scanned by 'best_path'
+ * create_tidscan_plan
+ * Returns a tidscan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static TidScan *
-create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
+create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
{
- TidScan *scan_node;
+ TidScan *scan_plan;
Index scan_relid;
/* there should be exactly one base rel involved... */
@@ -465,28 +498,28 @@ create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
scan_relid = (Index) lfirsti(best_path->path.parent->relids);
- scan_node = make_tidscan(tlist,
+ scan_plan = make_tidscan(tlist,
scan_clauses,
scan_relid,
best_path->tideval);
if (best_path->unjoined_relids)
- scan_node->needRescan = true;
+ scan_plan->needRescan = true;
- copy_path_costsize(&scan_node->scan.plan, &best_path->path);
+ copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
- return scan_node;
+ return scan_plan;
}
/*
- * create_subqueryscan_node
- * Returns a subqueryscan node for the base relation scanned by 'best_path'
+ * create_subqueryscan_plan
+ * Returns a subqueryscan plan for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static SubqueryScan *
-create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses)
+create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
{
- SubqueryScan *scan_node;
+ SubqueryScan *scan_plan;
Index scan_relid;
/* there should be exactly one base rel involved... */
@@ -496,14 +529,12 @@ create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses)
scan_relid = (Index) lfirsti(best_path->parent->relids);
- scan_node = make_subqueryscan(tlist,
+ scan_plan = make_subqueryscan(tlist,
scan_clauses,
scan_relid,
best_path->parent->subplan);
- copy_path_costsize(&scan_node->scan.plan, best_path);
-
- return scan_node;
+ return scan_plan;
}
/*****************************************************************************
@@ -528,18 +559,18 @@ create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses)
*****************************************************************************/
static NestLoop *
-create_nestloop_node(NestPath *best_path,
+create_nestloop_plan(NestPath *best_path,
List *tlist,
List *joinclauses,
List *otherclauses,
- Plan *outer_node,
+ Plan *outer_plan,
List *outer_tlist,
- Plan *inner_node,
+ Plan *inner_plan,
List *inner_tlist)
{
- NestLoop *join_node;
+ NestLoop *join_plan;
- if (IsA(inner_node, IndexScan))
+ if (IsA(inner_plan, IndexScan))
{
/*
@@ -563,7 +594,7 @@ create_nestloop_node(NestPath *best_path,
* and therefore has not itself done join_references renumbering
* of the vars in its quals.
*/
- IndexScan *innerscan = (IndexScan *) inner_node;
+ IndexScan *innerscan = (IndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig;
/* No work needed if indxqual refers only to its own relation... */
@@ -591,23 +622,23 @@ create_nestloop_node(NestPath *best_path,
NIL,
innerrel);
/* fix the inner qpqual too, if it has join clauses */
- if (NumRelids((Node *) inner_node->qual) > 1)
- inner_node->qual = join_references(inner_node->qual,
+ if (NumRelids((Node *) inner_plan->qual) > 1)
+ inner_plan->qual = join_references(inner_plan->qual,
outer_tlist,
NIL,
innerrel);
}
}
- else if (IsA(inner_node, TidScan))
+ else if (IsA(inner_plan, TidScan))
{
- TidScan *innerscan = (TidScan *) inner_node;
+ TidScan *innerscan = (TidScan *) inner_plan;
innerscan->tideval = join_references(innerscan->tideval,
outer_tlist,
inner_tlist,
innerscan->scan.scanrelid);
}
- else if (IsA_Join(inner_node))
+ else if (IsA_Join(inner_plan))
{
/*
@@ -617,8 +648,8 @@ create_nestloop_node(NestPath *best_path,
* join --- how can we estimate whether this is a good thing to
* do?
*/
- inner_node = (Plan *) make_material(inner_tlist,
- inner_node);
+ inner_plan = (Plan *) make_material(inner_tlist,
+ inner_plan);
}
/*
@@ -633,30 +664,30 @@ create_nestloop_node(NestPath *best_path,
inner_tlist,
(Index) 0);
- join_node = make_nestloop(tlist,
+ join_plan = make_nestloop(tlist,
joinclauses,
otherclauses,
- outer_node,
- inner_node,
+ outer_plan,
+ inner_plan,
best_path->jointype);
- copy_path_costsize(&join_node->join.plan, &best_path->path);
+ copy_path_costsize(&join_plan->join.plan, &best_path->path);
- return join_node;
+ return join_plan;
}
static MergeJoin *
-create_mergejoin_node(MergePath *best_path,
+create_mergejoin_plan(MergePath *best_path,
List *tlist,
List *joinclauses,
List *otherclauses,
- Plan *outer_node,
+ Plan *outer_plan,
List *outer_tlist,
- Plan *inner_node,
+ Plan *inner_plan,
List *inner_tlist)
{
List *mergeclauses;
- MergeJoin *join_node;
+ MergeJoin *join_plan;
mergeclauses = get_actual_clauses(best_path->path_mergeclauses);
@@ -692,15 +723,15 @@ create_mergejoin_node(MergePath *best_path,
* necessary. The sort cost was already accounted for in the path.
*/
if (best_path->outersortkeys)
- outer_node = (Plan *)
+ outer_plan = (Plan *)
make_sort_from_pathkeys(outer_tlist,
- outer_node,
+ outer_plan,
best_path->outersortkeys);
if (best_path->innersortkeys)
- inner_node = (Plan *)
+ inner_plan = (Plan *)
make_sort_from_pathkeys(inner_tlist,
- inner_node,
+ inner_plan,
best_path->innersortkeys);
/*
@@ -723,7 +754,7 @@ create_mergejoin_node(MergePath *best_path,
* This check must agree with ExecMarkPos/ExecRestrPos in
* executor/execAmi.c!
*/
- switch (nodeTag(inner_node))
+ switch (nodeTag(inner_plan))
{
case T_SeqScan:
case T_IndexScan:
@@ -734,40 +765,40 @@ create_mergejoin_node(MergePath *best_path,
default:
/* Ooops, need to materialize the inner plan */
- inner_node = (Plan *) make_material(inner_tlist,
- inner_node);
+ inner_plan = (Plan *) make_material(inner_tlist,
+ inner_plan);
break;
}
/*
* Now we can build the mergejoin node.
*/
- join_node = make_mergejoin(tlist,
+ join_plan = make_mergejoin(tlist,
joinclauses,
otherclauses,
mergeclauses,
- outer_node,
- inner_node,
+ outer_plan,
+ inner_plan,
best_path->jpath.jointype);
- copy_path_costsize(&join_node->join.plan, &best_path->jpath.path);
+ copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);
- return join_node;
+ return join_plan;
}
static HashJoin *
-create_hashjoin_node(HashPath *best_path,
+create_hashjoin_plan(HashPath *best_path,
List *tlist,
List *joinclauses,
List *otherclauses,
- Plan *outer_node,
+ Plan *outer_plan,
List *outer_tlist,
- Plan *inner_node,
+ Plan *inner_plan,
List *inner_tlist)
{
List *hashclauses;
- HashJoin *join_node;
- Hash *hash_node;
+ HashJoin *join_plan;
+ Hash *hash_plan;
Node *innerhashkey;
/*
@@ -811,18 +842,18 @@ create_hashjoin_node(HashPath *best_path,
/*
* Build the hash node and hash join node.
*/
- hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
- join_node = make_hashjoin(tlist,
+ hash_plan = make_hash(inner_tlist, innerhashkey, inner_plan);
+ join_plan = make_hashjoin(tlist,
joinclauses,
otherclauses,
hashclauses,
- outer_node,
- (Plan *) hash_node,
+ outer_plan,
+ (Plan *) hash_plan,
best_path->jpath.jointype);
- copy_path_costsize(&join_node->join.plan, &best_path->jpath.path);
+ copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);
- return join_node;
+ return join_plan;
}
@@ -1106,7 +1137,7 @@ copy_path_costsize(Plan *dest, Path *src)
* but it helps produce more reasonable-looking EXPLAIN output.
* (Some callers alter the info after copying it.)
*/
-void
+static void
copy_plan_costsize(Plan *dest, Plan *src)
{
if (src)
@@ -1128,6 +1159,10 @@ copy_plan_costsize(Plan *dest, Plan *src)
/*****************************************************************************
*
+ * PLAN NODE BUILDING ROUTINES
+ *
+ * Some of these are exported because they are called to build plan nodes
+ * in contexts where we're not deriving the plan node from a path node.
*
*****************************************************************************/
@@ -1212,7 +1247,7 @@ make_subqueryscan(List *qptlist,
SubqueryScan *node = makeNode(SubqueryScan);
Plan *plan = &node->scan.plan;
- /* cost should be inserted by caller */
+ copy_plan_costsize(plan, subplan);
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
@@ -1225,6 +1260,39 @@ make_subqueryscan(List *qptlist,
return node;
}
+Append *
+make_append(List *appendplans, bool isTarget, List *tlist)
+{
+ Append *node = makeNode(Append);
+ Plan *plan = &node->plan;
+ List *subnode;
+
+ /* compute costs from subplan costs */
+ plan->startup_cost = 0;
+ plan->total_cost = 0;
+ plan->plan_rows = 0;
+ plan->plan_width = 0;
+ foreach(subnode, appendplans)
+ {
+ Plan *subplan = (Plan *) lfirst(subnode);
+
+ if (subnode == appendplans) /* first node? */
+ plan->startup_cost = subplan->startup_cost;
+ plan->total_cost += subplan->total_cost;
+ plan->plan_rows += subplan->plan_rows;
+ if (plan->plan_width < subplan->plan_width)
+ plan->plan_width = subplan->plan_width;
+ }
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = NULL;
+ plan->righttree = NULL;
+ node->appendplans = appendplans;
+ node->isTarget = isTarget;
+
+ return node;
+}
static NestLoop *
make_nestloop(List *tlist,
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index a9747b32799..1a923a506ff 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.61 2000/10/05 19:11:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.62 2000/11/12 00:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -65,7 +65,8 @@ static Plan *subplanner(Query *root, List *flat_tlist,
* tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
* expected to be retrieved (ie, a LIMIT specification)
* Note that while this routine and its subroutines treat a negative
- * tuple_fraction the same as 0, union_planner has a different interpretation.
+ * tuple_fraction the same as 0, grouping_planner has a different
+ * interpretation.
*
* Returns a query plan.
*--------------------
@@ -125,9 +126,16 @@ query_planner(Query *root,
subplan = subplanner(root, var_only_tlist, tuple_fraction);
/*
- * Build a result node to control the plan if we have constant quals.
+ * Build a result node to control the plan if we have constant quals,
+ * or if the top-level plan node is one that cannot do expression
+ * evaluation (it won't be able to evaluate the requested tlist).
+ * Currently, the only plan node we might see here that falls into
+ * that category is Append.
+ *
+ * XXX future improvement: if the given tlist is flat anyway, we don't
+ * really need a Result node.
*/
- if (constant_quals)
+ if (constant_quals || IsA(subplan, Append))
{
/*
@@ -325,8 +333,8 @@ subplanner(Query *root,
/*
* Nothing for it but to sort the cheapest-total-cost path --- but we
- * let the caller do that. union_planner has to be able to add a sort
- * node anyway, so no need for extra code here. (Furthermore, the
+ * let the caller do that. grouping_planner has to be able to add a
+ * sort node anyway, so no need for extra code here. (Furthermore, the
* given pathkeys might involve something we can't compute here, such
* as an aggregate function...)
*/
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 67089e68d29..7a1151f0c9a 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.95 2000/11/09 02:46:16 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.96 2000/11/12 00:36:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,8 @@ static void resolvenew_in_jointree(Node *jtnode, int varno, List *subtlist);
static Node *preprocess_jointree(Query *parse, Node *jtnode);
static Node *preprocess_expression(Query *parse, Node *expr, int kind);
static void preprocess_qual_conditions(Query *parse, Node *jtnode);
+static Plan *inheritance_planner(Query *parse, List *inheritlist);
+static Plan *grouping_planner(Query *parse, double tuple_fraction);
static List *make_subplanTargetList(Query *parse, List *tlist,
AttrNumber **groupColIdx);
static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,
@@ -65,7 +67,7 @@ planner(Query *parse)
/*
* The planner can be called recursively (an example is when
- * eval_const_expressions tries to simplify an SQL function).
+ * eval_const_expressions tries to pre-evaluate an SQL function).
* So, these global state variables must be saved and restored.
*
* These vars cannot be moved into the Query structure since their
@@ -109,11 +111,14 @@ planner(Query *parse)
*
* parse is the querytree produced by the parser & rewriter.
* tuple_fraction is the fraction of tuples we expect will be retrieved.
- * tuple_fraction is interpreted as explained for union_planner, below.
+ * tuple_fraction is interpreted as explained for grouping_planner, below.
*
* Basically, this routine does the stuff that should only be done once
- * per Query object. It then calls union_planner, which may be called
- * recursively on the same Query node in order to handle inheritance.
+ * per Query object. It then calls grouping_planner. At one time,
+ * grouping_planner could be invoked recursively on the same Query object;
+ * that's not currently true, but we keep the separation between the two
+ * routines anyway, in case we need it again someday.
+ *
* subquery_planner will be called recursively to handle sub-Query nodes
* found within the query's expressions and rangetable.
*
@@ -164,7 +169,7 @@ subquery_planner(Query *parse, double tuple_fraction)
}
/*
- * Do preprocessing on targetlist and quals.
+ * Do expression preprocessing on targetlist and quals.
*/
parse->targetList = (List *)
preprocess_expression(parse, (Node *) parse->targetList,
@@ -176,17 +181,14 @@ subquery_planner(Query *parse, double tuple_fraction)
EXPRKIND_HAVING);
/*
- * Do the main planning (potentially recursive for inheritance)
- */
- plan = union_planner(parse, tuple_fraction);
-
- /*
- * XXX should any more of union_planner's activity be moved here?
- *
- * That would take careful study of the interactions with prepunion.c,
- * but I suspect it would pay off in simplicity and avoidance of
- * wasted cycles.
+ * Do the main planning. If we have an inherited target relation,
+ * that needs special processing, else go straight to grouping_planner.
*/
+ if (parse->resultRelation &&
+ (lst = expand_inherted_rtentry(parse, parse->resultRelation)) != NIL)
+ plan = inheritance_planner(parse, lst);
+ else
+ plan = grouping_planner(parse, tuple_fraction);
/*
* If any subplans were generated, or if we're inside a subplan,
@@ -600,10 +602,65 @@ preprocess_qual_conditions(Query *parse, Node *jtnode)
}
/*--------------------
- * union_planner
- * Invokes the planner on union-type queries (both set operations and
- * appends produced by inheritance), recursing if necessary to get them
- * all, then processes normal plans.
+ * 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.
+ *
+ * parse is the querytree produced by the parser & rewriter.
+ * inheritlist is an integer list of RT indexes for the result relation set.
+ *
+ * Returns a query plan.
+ *--------------------
+ */
+static Plan *
+inheritance_planner(Query *parse, List *inheritlist)
+{
+ int parentRTindex = parse->resultRelation;
+ Oid parentOID = getrelid(parentRTindex, parse->rtable);
+ List *subplans = NIL;
+ List *tlist = NIL;
+ List *l;
+
+ foreach(l, inheritlist)
+ {
+ int childRTindex = lfirsti(l);
+ Oid childOID = getrelid(childRTindex, parse->rtable);
+ Query *subquery;
+ Plan *subplan;
+
+ /* Generate modified query with this rel as target */
+ subquery = (Query *) adjust_inherited_attrs((Node *) parse,
+ parentRTindex, parentOID,
+ childRTindex, childOID);
+ /* Generate plan */
+ subplan = grouping_planner(subquery, 0.0 /* retrieve all tuples */);
+ subplans = lappend(subplans, subplan);
+ /* 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;
+
+ return (Plan *) make_append(subplans, true, tlist);
+}
+
+/*--------------------
+ * grouping_planner
+ * Perform planning steps related to grouping, aggregation, etc.
+ * This primarily means adding top-level processing to the basic
+ * query plan produced by query_planner.
*
* parse is the querytree produced by the parser & rewriter.
* tuple_fraction is the fraction of tuples we expect will be retrieved
@@ -621,18 +678,15 @@ preprocess_qual_conditions(Query *parse, Node *jtnode)
* Returns a query plan.
*--------------------
*/
-Plan *
-union_planner(Query *parse,
- double tuple_fraction)
+static Plan *
+grouping_planner(Query *parse, double tuple_fraction)
{
List *tlist = parse->targetList;
- Plan *result_plan = (Plan *) NULL;
- AttrNumber *groupColIdx = NULL;
- List *current_pathkeys = NIL;
+ Plan *result_plan;
+ List *current_pathkeys;
List *group_pathkeys;
List *sort_pathkeys;
- Index rt_index;
- List *inheritors;
+ AttrNumber *groupColIdx = NULL;
if (parse->setOperations)
{
@@ -654,12 +708,13 @@ union_planner(Query *parse,
tlist = postprocess_setop_tlist(result_plan->targetlist, tlist);
/*
- * We leave current_pathkeys NIL indicating we do not know sort
+ * We set current_pathkeys NIL indicating we do not know sort
* order. This is correct when the top set operation is UNION ALL,
* since the appended-together results are unsorted even if the
* subplans were sorted. For other set operations we could be
- * smarter --- future improvement!
+ * smarter --- room for future improvement!
*/
+ current_pathkeys = NIL;
/*
* Calculate pathkeys that represent grouping/ordering
@@ -670,54 +725,6 @@ union_planner(Query *parse,
sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause,
tlist);
}
- else if (find_inheritable_rt_entry(parse->rtable,
- &rt_index, &inheritors))
- {
- List *sub_tlist;
-
- /*
- * Generate appropriate target list for subplan; may be different
- * from tlist if grouping or aggregation is needed.
- */
- sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx);
-
- /*
- * Recursively plan the subqueries needed for inheritance
- */
- result_plan = plan_inherit_queries(parse, sub_tlist,
- rt_index, inheritors);
-
- /*
- * Fix up outer target list. NOTE: unlike the case for
- * non-inherited query, we pass the unfixed tlist to subplans,
- * which do their own fixing. But we still want to fix the outer
- * target list afterwards. I *think* this is correct --- doing the
- * fix before recursing is definitely wrong, because
- * preprocess_targetlist() will do the wrong thing if invoked
- * twice on the same list. Maybe that is a bug? tgl 6/6/99
- */
- tlist = preprocess_targetlist(tlist,
- parse->commandType,
- parse->resultRelation,
- parse->rtable);
-
- if (parse->rowMarks)
- elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries");
-
- /*
- * We leave current_pathkeys NIL indicating we do not know sort
- * order of the Append-ed results.
- */
-
- /*
- * Calculate pathkeys that represent grouping/ordering
- * requirements
- */
- group_pathkeys = make_pathkeys_for_sortclauses(parse->groupClause,
- tlist);
- sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause,
- tlist);
- }
else
{
List *sub_tlist;
@@ -938,10 +945,6 @@ union_planner(Query *parse,
current_pathkeys = parse->query_pathkeys;
}
- /* query_planner returns NULL if it thinks plan is bogus */
- if (!result_plan)
- elog(ERROR, "union_planner: failed to create plan");
-
/*
* We couldn't canonicalize group_pathkeys and sort_pathkeys before
* running query_planner(), so do it now.
@@ -1057,7 +1060,7 @@ union_planner(Query *parse,
* make_subplanTargetList
* Generate appropriate target list when grouping is required.
*
- * When union_planner inserts Aggregate and/or Group plan nodes above
+ * When grouping_planner inserts Aggregate and/or Group plan nodes above
* the result of query_planner, we typically want to pass a different
* target list to query_planner than the outer plan nodes should have.
* This routine generates the correct target list for the subplan.
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index ea9b902bc5b..ebb09f59393 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1,15 +1,20 @@
/*-------------------------------------------------------------------------
*
* prepunion.c
- * Routines to plan set-operation and inheritance queries. The filename
- * is a leftover from a time when only UNIONs were handled.
+ * Routines to plan set-operation queries. The filename is a leftover
+ * from a time when only UNIONs were implemented.
+ *
+ * There is also some code here to support planning of queries that use
+ * inheritance (SELECT FROM foo*). This no longer has much connection
+ * to the processing of UNION queries, but it's still here.
+ *
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.55 2000/11/09 02:46:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.56 2000/11/12 00:36:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,13 +35,19 @@
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
+/* macros borrowed from expression_tree_mutator */
+
+#define FLATCOPY(newnode, node, nodetype) \
+ ( (newnode) = makeNode(nodetype), \
+ memcpy((newnode), (node), sizeof(nodetype)) )
+
typedef struct
{
- Index rt_index;
- int sublevels_up;
+ Index old_rt_index;
+ Index new_rt_index;
Oid old_relid;
Oid new_relid;
-} fix_parsetree_attnums_context;
+} adjust_inherited_attrs_context;
static Plan *recurse_set_operations(Node *setOp, Query *parse,
List *colTypes, bool junkOK,
@@ -53,14 +64,8 @@ static List *generate_setop_tlist(List *colTypes, int flag,
List *input_tlist,
List *refnames_tlist);
static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK);
-static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
- Oid new_relid, Query *parsetree);
-static bool fix_parsetree_attnums_walker(Node *node,
- fix_parsetree_attnums_context *context);
-static RangeTblEntry *new_rangetable_entry(Oid new_relid,
- RangeTblEntry *old_entry);
-static Append *make_append(List *appendplans, Index rt_index,
- List *inheritrtable, List *tlist);
+static Node *adjust_inherited_attrs_mutator(Node *node,
+ adjust_inherited_attrs_context *context);
/*
@@ -69,8 +74,8 @@ static Append *make_append(List *appendplans, Index rt_index,
* Plans the queries for a tree of set operations (UNION/INTERSECT/EXCEPT)
*
* This routine only deals with the setOperations tree of the given query.
- * Any top-level ORDER BY requested in parse->sortClause will be added on
- * back in union_planner.
+ * Any top-level ORDER BY requested in parse->sortClause will be added
+ * when we return to grouping_planner.
*/
Plan *
plan_set_operations(Query *parse)
@@ -142,7 +147,6 @@ recurse_set_operations(Node *setOp, Query *parse,
NIL,
rtr->rtindex,
subplan);
- copy_plan_costsize(plan, subplan);
return plan;
}
else if (IsA(setOp, SetOperationStmt))
@@ -217,8 +221,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
*/
plan = (Plan *)
make_append(planlist,
- 0,
- NIL,
+ false,
generate_setop_tlist(op->colTypes, -1, false,
((Plan *) lfirst(planlist))->targetlist,
refnames_tlist));
@@ -269,8 +272,7 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
*/
plan = (Plan *)
make_append(makeList2(lplan, rplan),
- 0,
- NIL,
+ false,
generate_setop_tlist(op->colTypes, 0, false,
lplan->targetlist,
refnames_tlist));
@@ -457,132 +459,6 @@ tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
/*
- * plan_inherit_queries
- * Plans the queries for an inheritance tree rooted at a parent relation.
- *
- * Inputs:
- * root = parent parse tree
- * tlist = target list for inheritance subqueries (not same as parent's!)
- * rt_index = rangetable index for current inheritance item
- * inheritors = list of OIDs of the target rel plus all its descendants
- *
- * Returns an APPEND node that forms the result of performing the given
- * query for each member relation of the inheritance group.
- *
- * If grouping, aggregation, or sorting is specified in the parent plan,
- * the subplans should not do any of those steps --- we must do those
- * operations just once above the APPEND node. The given tlist has been
- * modified appropriately to remove group/aggregate expressions, but the
- * Query node still has the relevant fields set. We remove them in the
- * copies used for subplans.
- *
- * NOTE: this can be invoked recursively if more than one inheritance wildcard
- * is present. At each level of recursion, the first wildcard remaining in
- * the rangetable is expanded.
- *
- * NOTE: don't bother optimizing this routine for the case that the target
- * rel has no children. We won't get here unless find_inheritable_rt_entry
- * found at least two members in the inheritance group, so an APPEND is
- * certainly necessary.
- */
-Plan *
-plan_inherit_queries(Query *root, List *tlist,
- Index rt_index, List *inheritors)
-{
- RangeTblEntry *rt_entry = rt_fetch(rt_index, root->rtable);
- List *union_plans = NIL;
- List *union_rtentries = NIL;
- List *save_tlist = root->targetList;
- double tuple_fraction;
- 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). This is purely a space-saving hack. Note we restore
- * the root's tlist before exiting.
- */
- root->targetList = NIL;
-
- /*
- * If we are going to need sorting or grouping at the top level, force
- * lower-level planners to assume that all tuples will be retrieved.
- */
- if (root->distinctClause || root->sortClause ||
- root->groupClause || root->hasAggs)
- tuple_fraction = 0.0; /* will need all tuples from each subplan */
- else
- tuple_fraction = -1.0; /* default behavior is OK (I think) */
-
- foreach(i, inheritors)
- {
- Oid relid = lfirsti(i);
-
- /*
- * Make a modifiable copy of the original query, and replace the
- * target rangetable entry in it with a new one identifying this
- * child table. The new rtentry is marked inh = false --- this
- * is essential to prevent infinite recursion when the subquery
- * is rescanned by find_inheritable_rt_entry!
- */
- Query *new_root = copyObject(root);
- RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
- rt_entry);
-
- new_rt_entry->inh = false;
- rt_store(rt_index, new_root->rtable, new_rt_entry);
-
- /*
- * Insert (a modifiable copy of) the desired simplified tlist into
- * the subquery
- */
- new_root->targetList = copyObject(tlist);
-
- /*
- * Clear the sorting and grouping qualifications in the subquery,
- * so that sorting will only be done once after append
- */
- new_root->distinctClause = NIL;
- new_root->sortClause = NIL;
- new_root->groupClause = NIL;
- new_root->havingQual = NULL;
- new_root->limitOffset = NULL; /* LIMIT's probably unsafe too */
- new_root->limitCount = NULL;
- new_root->hasAggs = false; /* shouldn't be any left ... */
-
- /*
- * 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,
- rt_entry->relid,
- relid,
- new_root);
-
- /*
- * Plan the subquery by recursively calling union_planner().
- * Add plan and child rtentry to lists for APPEND.
- */
- union_plans = lappend(union_plans,
- union_planner(new_root, tuple_fraction));
- union_rtentries = lappend(union_rtentries, new_rt_entry);
- }
-
- /* Restore root's tlist */
- root->targetList = save_tlist;
-
- /* Construct the finished Append plan. */
- return (Plan *) make_append(union_plans,
- rt_index,
- union_rtentries,
- ((Plan *) lfirst(union_plans))->targetlist);
-}
-
-/*
* find_all_inheritors -
* Returns an integer list of relids including the given rel plus
* all relations that inherit from it, directly or indirectly.
@@ -622,200 +498,181 @@ find_all_inheritors(Oid parentrel)
}
/*
- * find_inheritable_rt_entry -
- * Given a rangetable, find the first rangetable entry that represents
- * an inheritance set.
- *
- * If successful, set *rt_index to the index (1..n) of the entry,
- * set *inheritors to a list of the relation OIDs of the set,
- * and return TRUE.
- *
- * If there is no entry that requires inheritance processing,
- * return FALSE.
+ * expand_inherted_rtentry
+ * Check whether a rangetable entry represents an inheritance set.
+ * If so, add entries for all the child tables to the query's
+ * rangetable, and return an integer list of RT indexes for the
+ * whole inheritance set (parent and children).
+ * If not, return NIL.
*
- * NOTE: We return the inheritors list so that plan_inherit_queries doesn't
- * have to compute it again.
+ * A childless table is never considered to be an inheritance set; therefore
+ * the result will never be a one-element list. It'll be either empty
+ * or have two or more elements.
*
- * NOTE: We clear the inh flag in any entries that have it set but turn
- * out not to have any actual inheritance children. This is an efficiency
- * hack to avoid having to repeat the inheritance checks if the list is
- * scanned again (as will happen during expansion of any subsequent entry
- * that does have inheritance children). Although modifying the input
- * rangetable in-place may seem uncool, there's no reason not to do it,
- * since any re-examination of the entry would just come to the same
- * conclusion that the table has no children.
+ * NOTE: after this routine executes, the specified RTE will always have
+ * its inh flag cleared, whether or not there were any children. This
+ * ensures we won't expand the same RTE twice, which would otherwise occur
+ * for the case of an inherited UPDATE/DELETE target relation.
*/
-bool
-find_inheritable_rt_entry(List *rangetable,
- Index *rt_index,
- List **inheritors)
+List *
+expand_inherted_rtentry(Query *parse, Index rti)
{
- Index count = 0;
- List *temp;
-
- foreach(temp, rangetable)
+ RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
+ Oid parentOID = rte->relid;
+ List *inhOIDs;
+ List *inhRTIs;
+ List *l;
+
+ /* Does RT entry allow inheritance? */
+ if (! rte->inh)
+ return NIL;
+ Assert(parentOID != InvalidOid && rte->subquery == NULL);
+ /* Always clear the parent's inh flag, see above comments */
+ rte->inh = false;
+ /* Fast path for common case of childless table */
+ if (! has_subclass(parentOID))
+ return NIL;
+ /* Scan for all members of inheritance set */
+ inhOIDs = find_all_inheritors(parentOID);
+ /*
+ * Check that there's at least one descendant, else treat as
+ * no-child case. This could happen despite above has_subclass()
+ * check, if table once had a child but no longer does.
+ */
+ if (lnext(inhOIDs) == NIL)
+ return NIL;
+ /* OK, it's an inheritance set; expand it */
+ inhRTIs = makeListi1(rti);
+ foreach(l, inhOIDs)
{
- RangeTblEntry *rt_entry = (RangeTblEntry *) lfirst(temp);
- List *inhs;
+ Oid childOID = (Oid) lfirsti(l);
+ RangeTblEntry *childrte;
+ Index childRTindex;
- count++;
- /* Ignore non-inheritable RT entries */
- if (! rt_entry->inh)
- continue;
- /* Fast path for common case of childless table */
- if (! has_subclass(rt_entry->relid))
- {
- rt_entry->inh = false;
+ /* parent will be in the list too, so ignore it */
+ if (childOID == parentOID)
continue;
- }
- /* Scan for all members of inheritance set */
- inhs = find_all_inheritors(rt_entry->relid);
+
/*
- * Check that there's at least one descendant, else treat as
- * no-child case. This could happen despite above has_subclass()
- * check, if table once had a child but no longer does.
+ * Build an RTE for the child, and attach to query's rangetable list.
+ * We copy most fields of the parent's RTE, but replace relation
+ * real name and OID. Note that inh will be false at this point.
*/
- if (lnext(inhs) == NIL)
- {
- rt_entry->inh = false;
- continue;
- }
- /* OK, found our boy */
- *rt_index = count;
- *inheritors = inhs;
- return true;
- }
+ childrte = copyObject(rte);
+ childrte->relname = get_rel_name(childOID);
+ childrte->relid = childOID;
+ parse->rtable = lappend(parse->rtable, childrte);
+ childRTindex = length(parse->rtable);
- return false;
-}
-
-/*
- * new_rangetable_entry -
- * Replaces the name and relid of 'old_entry' with the values for
- * 'new_relid'.
- *
- * Returns a copy of 'old_entry' with the parameters substituted.
- */
-static RangeTblEntry *
-new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
-{
- RangeTblEntry *new_entry = copyObject(old_entry);
-
- /* Replace relation real name and OID, but not the reference name */
- new_entry->relname = get_rel_name(new_relid);
- new_entry->relid = new_relid;
- return new_entry;
+ inhRTIs = lappendi(inhRTIs, childRTindex);
+ }
+ return inhRTIs;
}
/*
- * fix_parsetree_attnums
- * Replaces attribute numbers from the relation represented by
- * 'old_relid' in 'parsetree' with the attribute numbers from
- * 'new_relid'.
+ * adjust_inherited_attrs
+ * Copy the specified query or expression and translate Vars referring
+ * to old_rt_index to refer to new_rt_index.
*
- * The parsetree is MODIFIED IN PLACE. This is OK only because
- * plan_inherit_queries made a copy of the tree for us to hack upon.
+ * We also adjust varattno to match the new table by column name, rather
+ * than column number. This hack makes it possible for child tables to have
+ * different column positions for the "same" attribute as a parent, which
+ * helps ALTER TABLE ADD COLUMN. Unfortunately this isn't nearly enough to
+ * make it work transparently; there are other places where things fall down
+ * if children and parents don't have the same column numbers for inherited
+ * attributes. It'd be better to rip this code out and fix ALTER TABLE...
*/
-static void
-fix_parsetree_attnums(Index rt_index,
- Oid old_relid,
- Oid new_relid,
- Query *parsetree)
+Node *
+adjust_inherited_attrs(Node *node,
+ Index old_rt_index, Oid old_relid,
+ Index new_rt_index, Oid new_relid)
{
- fix_parsetree_attnums_context context;
+ adjust_inherited_attrs_context context;
- if (old_relid == new_relid)
- return; /* no work needed for parent rel itself */
+ /* Handle simple case simply... */
+ if (old_rt_index == new_rt_index)
+ {
+ Assert(old_relid == new_relid);
+ return copyObject(node);
+ }
- context.rt_index = rt_index;
+ context.old_rt_index = old_rt_index;
+ context.new_rt_index = new_rt_index;
context.old_relid = old_relid;
context.new_relid = new_relid;
- context.sublevels_up = 0;
- query_tree_walker(parsetree,
- fix_parsetree_attnums_walker,
- (void *) &context,
- true);
+ /*
+ * Must be prepared to start with a Query or a bare expression tree.
+ */
+ if (node && IsA(node, Query))
+ {
+ Query *query = (Query *) node;
+ Query *newnode;
+
+ FLATCOPY(newnode, query, Query);
+ if (newnode->resultRelation == old_rt_index)
+ newnode->resultRelation = new_rt_index;
+ query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
+ (void *) &context, false);
+ return (Node *) newnode;
+ }
+ else
+ return adjust_inherited_attrs_mutator(node, &context);
}
-/*
- * Adjust varnos for child tables. This routine makes it possible for
- * child tables to have different column positions for the "same" attribute
- * as a parent, which helps ALTER TABLE ADD COLUMN. Unfortunately this isn't
- * nearly enough to make it work transparently; there are other places where
- * things fall down if children and parents don't have the same column numbers
- * for inherited attributes. It'd be better to rip this code out and fix
- * ALTER TABLE...
- */
-static bool
-fix_parsetree_attnums_walker(Node *node,
- fix_parsetree_attnums_context *context)
+static Node *
+adjust_inherited_attrs_mutator(Node *node,
+ adjust_inherited_attrs_context *context)
{
if (node == NULL)
- return false;
+ return NULL;
if (IsA(node, Var))
{
- Var *var = (Var *) node;
+ Var *var = (Var *) copyObject(node);
- if (var->varlevelsup == context->sublevels_up &&
- var->varno == context->rt_index &&
- var->varattno > 0)
+ if (var->varlevelsup == 0 &&
+ var->varno == context->old_rt_index)
{
- var->varattno = get_attnum(context->new_relid,
- get_attname(context->old_relid,
- var->varattno));
+ var->varno = context->new_rt_index;
+ if (var->varattno > 0)
+ var->varattno = get_attnum(context->new_relid,
+ get_attname(context->old_relid,
+ var->varattno));
}
- return false;
+ return (Node *) var;
}
- if (IsA(node, Query))
+ if (IsA(node, RangeTblRef))
{
- /* Recurse into subselects */
- bool result;
-
- context->sublevels_up++;
- result = query_tree_walker((Query *) node,
- fix_parsetree_attnums_walker,
- (void *) context,
- true);
- context->sublevels_up--;
- return result;
- }
- return expression_tree_walker(node, fix_parsetree_attnums_walker,
- (void *) context);
-}
+ RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
-static Append *
-make_append(List *appendplans,
- Index rt_index,
- List *inheritrtable,
- List *tlist)
-{
- Append *node = makeNode(Append);
- List *subnode;
-
- node->appendplans = appendplans;
- node->inheritrelid = rt_index;
- node->inheritrtable = inheritrtable;
- node->plan.startup_cost = 0;
- node->plan.total_cost = 0;
- node->plan.plan_rows = 0;
- node->plan.plan_width = 0;
- foreach(subnode, appendplans)
- {
- Plan *subplan = (Plan *) lfirst(subnode);
-
- if (subnode == appendplans) /* first node? */
- node->plan.startup_cost = subplan->startup_cost;
- node->plan.total_cost += subplan->total_cost;
- node->plan.plan_rows += subplan->plan_rows;
- if (node->plan.plan_width < subplan->plan_width)
- node->plan.plan_width = subplan->plan_width;
+ if (rtr->rtindex == context->old_rt_index)
+ rtr->rtindex = context->new_rt_index;
+ return (Node *) rtr;
}
- node->plan.state = (EState *) NULL;
- node->plan.targetlist = tlist;
- node->plan.qual = NIL;
- node->plan.lefttree = (Plan *) NULL;
- node->plan.righttree = (Plan *) NULL;
+ /*
+ * We have to process RestrictInfo nodes specially: we do NOT want to
+ * copy the original subclauseindices list, since the new rel may have
+ * different indices. The list will be rebuilt during planning anyway.
+ */
+ if (IsA(node, RestrictInfo))
+ {
+ RestrictInfo *oldinfo = (RestrictInfo *) node;
+ RestrictInfo *newinfo = makeNode(RestrictInfo);
+
+ /* Copy all flat-copiable fields */
+ memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
+
+ newinfo->clause = (Expr *)
+ adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context);
- return node;
+ newinfo->subclauseindices = NIL;
+
+ return (Node *) newinfo;
+ }
+ /*
+ * NOTE: we do not need to recurse into sublinks, because they should
+ * already have been converted to subplans before we see them.
+ */
+ return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
+ (void *) context);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 36843f834da..b51ec089347 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.67 2000/10/05 19:48:27 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.68 2000/11/12 00:36:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -391,6 +391,37 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
}
/*
+ * create_append_path
+ * Creates a path corresponding to an Append plan, returning the
+ * pathnode.
+ *
+ */
+AppendPath *
+create_append_path(RelOptInfo *rel, List *subpaths)
+{
+ AppendPath *pathnode = makeNode(AppendPath);
+ List *l;
+
+ pathnode->path.pathtype = T_Append;
+ pathnode->path.parent = rel;
+ pathnode->path.pathkeys = NIL; /* result is always considered unsorted */
+ pathnode->subpaths = subpaths;
+
+ pathnode->path.startup_cost = 0;
+ pathnode->path.total_cost = 0;
+ foreach(l, subpaths)
+ {
+ Path *subpath = (Path *) lfirst(l);
+
+ if (l == subpaths) /* first node? */
+ pathnode->path.startup_cost = subpath->startup_cost;
+ pathnode->path.total_cost += subpath->total_cost;
+ }
+
+ return pathnode;
+}
+
+/*
* create_subqueryscan_path
* Creates a path corresponding to a sequential scan of a subquery,
* returning the pathnode.
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 86258b0f644..64720944ce3 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.29 2000/09/29 18:21:23 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.30 2000/11/12 00:36:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -45,7 +45,6 @@ get_base_rel(Query *root, int relid)
{
List *baserels;
RelOptInfo *rel;
- Oid relationObjectId;
foreach(baserels, root->base_rel_list)
{
@@ -60,7 +59,30 @@ get_base_rel(Query *root, int relid)
}
/* No existing RelOptInfo for this base rel, so make a new one */
- rel = makeNode(RelOptInfo);
+ rel = make_base_rel(root, relid);
+
+ /* and add it to the list */
+ root->base_rel_list = lcons(rel, root->base_rel_list);
+
+ return rel;
+}
+
+/*
+ * make_base_rel
+ * Construct a base-relation RelOptInfo for the specified rangetable index.
+ *
+ * This is split out of get_base_rel so that inheritance-tree processing can
+ * construct baserel nodes for child tables. We need a RelOptInfo so we can
+ * plan a suitable access path for each child table, but we do NOT want to
+ * enter the child nodes into base_rel_list. In most contexts, get_base_rel
+ * should be called instead.
+ */
+RelOptInfo *
+make_base_rel(Query *root, int relid)
+{
+ RelOptInfo *rel = makeNode(RelOptInfo);
+ Oid relationObjectId;
+
rel->relids = makeListi1(relid);
rel->rows = 0;
rel->width = 0;
@@ -95,8 +117,6 @@ get_base_rel(Query *root, int relid)
rel->issubquery = true;
}
- root->base_rel_list = lcons(rel, root->base_rel_list);
-
return rel;
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 60521d13475..cbd19f0aae4 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.71 2000/11/08 22:09:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.72 2000/11/12 00:37:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -151,8 +151,12 @@ setTargetTable(ParseState *pstate, char *relname, bool inh, bool inJoinSet)
/*
* Since the rel was in the rangetable already, it's being read
* as well as written. Therefore, leave checkForRead true.
+ *
+ * Force inh to the desired setting for the target (XXX is this
+ * reasonable? It's *necessary* that INSERT target not be marked
+ * inheritable, but otherwise not too clear what to do if conflict?)
*/
- /* XXX what if pre-existing entry has wrong inh setting? */
+ rte->inh = inh;
}
/* Mark target table as requiring write access. */
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 62848d77348..248baa3f894 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.39 2000/10/26 21:37:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.40 2000/11/12 00:37:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -68,7 +68,12 @@ CreateExecutorState(void)
state->es_direction = ForwardScanDirection;
state->es_range_table = NIL;
+ state->es_result_relations = NULL;
+ state->es_num_result_relations = 0;
state->es_result_relation_info = NULL;
+
+ state->es_junkFilter = NULL;
+
state->es_into_relation_descriptor = NULL;
state->es_param_list_info = NULL;
@@ -76,8 +81,6 @@ CreateExecutorState(void)
state->es_tupleTable = NULL;
- state->es_junkFilter = NULL;
-
state->es_query_cxt = CurrentMemoryContext;
state->es_per_tuple_exprcontext = NULL;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3deef21855f..67a2beb77c3 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.58 2000/11/11 19:55:33 thomas Exp $
+ * $Id: catversion.h,v 1.59 2000/11/12 00:37:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -52,7 +52,7 @@
* catalog changes on the same day...)
*/
-/* yyyymmddN */
-#define CATALOG_VERSION_NO 200011110
+/* yyyymmddN */
+#define CATALOG_VERSION_NO 200011112
#endif
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 9fe59b031a7..2197af567fd 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.52 2000/10/26 21:38:03 tgl Exp $
+ * $Id: executor.h,v 1.53 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,7 +56,7 @@ extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
int feature, long count);
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
-extern void ExecConstraints(char *caller, Relation rel,
+extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
ItemPointer tid);
@@ -153,8 +153,8 @@ extern void FreeExprContext(ExprContext *econtext);
#define ResetExprContext(econtext) \
MemoryContextReset((econtext)->ecxt_per_tuple_memory)
-extern void ExecOpenIndices(RelationInfo *resultRelationInfo);
-extern void ExecCloseIndices(RelationInfo *resultRelationInfo);
+extern void ExecOpenIndices(ResultRelInfo *resultRelInfo);
+extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
extern void ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate, bool is_update);
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index a8edfae6740..8aa0ba39ecd 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: tuptable.h,v 1.15 2000/01/26 05:58:06 momjian Exp $
+ * $Id: tuptable.h,v 1.16 2000/11/12 00:37:01 tgl Exp $
*
* NOTES
* The tuple table interface is getting pretty ugly.
@@ -56,7 +56,6 @@ typedef struct TupleTableSlot
bool ttc_descIsNew;
TupleDesc ttc_tupleDescriptor;
Buffer ttc_buffer;
- int ttc_whichplan;
} TupleTableSlot;
/* ----------------
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 14cd94baa07..4ba3a70c1b5 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execnodes.h,v 1.52 2000/10/26 21:38:12 tgl Exp $
+ * $Id: execnodes.h,v 1.53 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,31 +53,6 @@ typedef struct IndexInfo
} IndexInfo;
/* ----------------
- * RelationInfo information
- *
- * whenever we update an existing relation, we have to
- * update indices on the relation. The RelationInfo class
- * is used to hold all the information on result relations,
- * including indices.. -cim 10/15/89
- *
- * RangeTableIndex result relation's range table index
- * RelationDesc relation descriptor for result relation
- * NumIndices number indices existing on result relation
- * IndexRelationDescs array of relation descriptors for indices
- * IndexRelationInfo array of key/attr info for indices
- * ----------------
- */
-typedef struct RelationInfo
-{
- NodeTag type;
- Index ri_RangeTableIndex;
- Relation ri_RelationDesc;
- int ri_NumIndices;
- RelationPtr ri_IndexRelationDescs;
- IndexInfo **ri_IndexRelationInfo;
-} RelationInfo;
-
-/* ----------------
* ExprContext
*
* This class holds the "current context" information
@@ -116,8 +91,6 @@ typedef struct ExprContext
/* Values to substitute for Aggref nodes in expression */
Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
bool *ecxt_aggnulls; /* null flags for Aggref nodes */
- /* Range table that Vars in expression refer to --- seldom needed */
- List *ecxt_range_table;
} ExprContext;
/*
@@ -211,13 +184,42 @@ typedef struct JunkFilter
} JunkFilter;
/* ----------------
+ * ResultRelInfo information
+ *
+ * whenever we update an existing relation, we have to
+ * update indices on the relation. The ResultRelInfo class
+ * is used to hold all the information on result relations,
+ * including indices.. -cim 10/15/89
+ *
+ * RangeTableIndex result relation's range table index
+ * RelationDesc relation descriptor for result relation
+ * NumIndices # of indices existing on result relation
+ * IndexRelationDescs array of relation descriptors for indices
+ * IndexRelationInfo array of key/attr info for indices
+ * ConstraintExprs array of constraint-checking expressions
+ * junkFilter for removing junk attributes from tuples
+ * ----------------
+ */
+typedef struct ResultRelInfo
+{
+ NodeTag type;
+ Index ri_RangeTableIndex;
+ Relation ri_RelationDesc;
+ int ri_NumIndices;
+ RelationPtr ri_IndexRelationDescs;
+ IndexInfo **ri_IndexRelationInfo;
+ List **ri_ConstraintExprs;
+ JunkFilter *ri_junkFilter;
+} ResultRelInfo;
+
+/* ----------------
* EState information
*
* direction direction of the scan
*
* range_table array of scan relation information
*
- * result_relation_information for update queries
+ * result_relation information for insert/update/delete queries
*
* into_relation_descriptor relation being retrieved "into"
*
@@ -227,10 +229,6 @@ typedef struct JunkFilter
* tupleTable this is a pointer to an array
* of pointers to tuples used by
* the executor at any given moment.
- *
- * junkFilter contains information used to
- * extract junk attributes from a tuple.
- * (see JunkFilter above)
* ----------------
*/
typedef struct EState
@@ -239,23 +237,24 @@ typedef struct EState
ScanDirection es_direction;
Snapshot es_snapshot;
List *es_range_table;
- RelationInfo *es_result_relation_info;
+ ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
+ int es_num_result_relations; /* length of array */
+ ResultRelInfo *es_result_relation_info; /* currently active array elt */
+ JunkFilter *es_junkFilter; /* currently active junk filter */
Relation es_into_relation_descriptor;
ParamListInfo es_param_list_info;
ParamExecData *es_param_exec_vals; /* this is for subselects */
TupleTable es_tupleTable;
- JunkFilter *es_junkFilter;
uint32 es_processed; /* # of tuples processed */
Oid es_lastoid; /* last oid processed (by INSERT) */
List *es_rowMark; /* not good place, but there is no other */
MemoryContext es_query_cxt; /* per-query context in which EState lives */
- /* this ExprContext is for per-output-tuple operations, such as
+ /*
+ * this ExprContext is for per-output-tuple operations, such as
* constraint checks and index-value computations. It can be reset
* for each output tuple. Note that it will be created only if needed.
*/
ExprContext *es_per_tuple_exprcontext;
- /* this field is storage space for ExecConstraints(): */
- List **es_result_relation_constraints;
/* Below is to re-evaluate plan qual in READ COMMITTED mode */
struct Plan *es_origPlan;
Pointer es_evalPlanQual;
@@ -341,15 +340,9 @@ typedef struct ResultState
/* ----------------
* AppendState information
*
- * append nodes have this field "unionplans" which is this
- * list of plans to execute in sequence.. these variables
- * keep track of things..
- *
- * whichplan which plan is being executed
+ * whichplan which plan is being executed (0 .. n-1)
* nplans how many plans are in the list
* initialized array of ExecInitNode() results
- * result_relation_info_list array of each subplan's result relation info
- * junkFilter_list array of each subplan's junk filter
* ----------------
*/
typedef struct AppendState
@@ -358,8 +351,6 @@ typedef struct AppendState
int as_whichplan;
int as_nplans;
bool *as_initialized;
- List *as_result_relation_info_list;
- List *as_junkFilter_list;
} AppendState;
/* ----------------------------------------------------------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 727db39d827..6b64961525a 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.82 2000/11/05 22:50:21 vadim Exp $
+ * $Id: nodes.h,v 1.83 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -83,11 +83,12 @@ typedef enum NodeTag
T_NestPath,
T_MergePath,
T_HashPath,
+ T_TidPath,
+ T_AppendPath,
T_PathKeyItem,
T_RestrictInfo,
T_JoinInfo,
T_Stream,
- T_TidPath,
T_IndexOptInfo,
/*---------------------
@@ -95,7 +96,7 @@ typedef enum NodeTag
*---------------------
*/
T_IndexInfo = 300,
- T_RelationInfo,
+ T_ResultRelInfo,
T_TupleCount,
T_TupleTableSlot,
T_ExprContext,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 269fa9592be..469230e1c62 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.119 2000/11/05 22:50:21 vadim Exp $
+ * $Id: parsenodes.h,v 1.120 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -70,6 +70,16 @@ typedef struct Query
Node *setOperations; /* set-operation tree if this is top level
* of a UNION/INTERSECT/EXCEPT query */
+ /*
+ * If the resultRelation turns out to be the parent of an inheritance
+ * tree, the planner will add all the child tables to the rtable and
+ * store a list of the rtindexes of all the result relations here.
+ * This is done at plan time, not parse time, since we don't want to
+ * commit to the exact set of child tables at parse time. This field
+ * ought to go in some sort of TopPlan plan node, not in the Query.
+ */
+ List *resultRelations; /* integer list of RT indexes, or NIL */
+
/* internal to planner */
List *base_rel_list; /* list of base-relation RelOptInfos */
List *join_rel_list; /* list of join-relation RelOptInfos */
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 177ab73a13b..eecb74caf2f 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: plannodes.h,v 1.45 2000/10/26 21:38:12 tgl Exp $
+ * $Id: plannodes.h,v 1.46 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -134,8 +134,10 @@ typedef struct Plan
/* ----------------
- * result node -
- * returns tuples from outer plan that satisfy the qualifications
+ * Result node -
+ * If no outer plan, evaluate a variable-free targetlist.
+ * If outer plan, return tuples from outer plan that satisfy
+ * given quals (we can also do a level of projection)
* ----------------
*/
typedef struct Result
@@ -146,21 +148,21 @@ typedef struct Result
} Result;
/* ----------------
- * append node
+ * Append node -
+ * Generate the concatenation of the results of sub-plans.
*
- * Append nodes can modify the query's rtable during execution.
- * If inheritrelid > 0, then the RTE with index inheritrelid is replaced
- * by the i'th element of inheritrtable to execute the i'th subplan.
- * We assume that this RTE is not used in any other part of the
- * query plan tree, else confusion may result...
+ * Append nodes are sometimes used to switch between several result relations
+ * (when the target of an UPDATE or DELETE is an inheritance set). Such a
+ * node will have isTarget true. The Append executor is then responsible
+ * for updating the executor state to point at the correct target relation
+ * whenever it switches subplans.
* ----------------
*/
typedef struct Append
{
Plan plan;
List *appendplans;
- Index inheritrelid;
- List *inheritrtable;
+ bool isTarget;
AppendState *appendstate;
} Append;
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 1c864f2e721..45d53be5f62 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: relation.h,v 1.49 2000/09/29 18:21:39 tgl Exp $
+ * $Id: relation.h,v 1.50 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -82,6 +82,14 @@ typedef enum CostSelector
* upon creation of the RelOptInfo object; they are filled in when
* set_base_rel_pathlist processes the object.
*
+ * Note: if a base relation is the root of an inheritance tree
+ * (SELECT FROM foo*) it is still considered a base rel. We will
+ * generate a list of candidate Paths for accessing that table itself,
+ * and also generate baserel RelOptInfo nodes for each child table,
+ * with their own candidate Path lists. Then, an AppendPath is built
+ * from the cheapest Path for each of these tables, and set to be the
+ * only available Path for the inheritance baserel.
+ *
* * The presence of the remaining fields depends on the restrictions
* and joins that the relation participates in:
*
@@ -313,6 +321,9 @@ typedef struct IndexPath
double rows; /* estimated number of result tuples */
} IndexPath;
+/*
+ * TidPath represents a scan by TID
+ */
typedef struct TidPath
{
Path path;
@@ -321,6 +332,17 @@ typedef struct TidPath
} TidPath;
/*
+ * AppendPath represents an Append plan, ie, successive execution of
+ * several member plans. Currently it is only used to handle expansion
+ * of inheritance trees.
+ */
+typedef struct AppendPath
+{
+ Path path;
+ List *subpaths; /* list of component Paths */
+} AppendPath;
+
+/*
* All join-type paths share these fields.
*/
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 06912f192f6..993003eaa2f 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pathnode.h,v 1.30 2000/10/05 19:48:33 momjian Exp $
+ * $Id: pathnode.h,v 1.31 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,6 +32,7 @@ extern IndexPath *create_index_path(Query *root, RelOptInfo *rel,
List *restriction_clauses,
ScanDirection indexscandir);
extern TidPath *create_tidscan_path(RelOptInfo *rel, List *tideval);
+extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths);
extern Path *create_subqueryscan_path(RelOptInfo *rel);
extern NestPath *create_nestloop_path(RelOptInfo *joinrel,
@@ -63,6 +64,7 @@ extern HashPath *create_hashjoin_path(RelOptInfo *joinrel,
* prototypes for relnode.c
*/
extern RelOptInfo *get_base_rel(Query *root, int relid);
+extern RelOptInfo *make_base_rel(Query *root, int relid);
extern RelOptInfo *get_join_rel(Query *root, RelOptInfo *outer_rel,
RelOptInfo *inner_rel,
List **restrictlist_ptr);
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 2d5de645046..f50c1113f06 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: planmain.h,v 1.47 2000/10/26 21:38:24 tgl Exp $
+ * $Id: planmain.h,v 1.48 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@ extern Plan *query_planner(Query *root, List *tlist, double tuple_fraction);
extern Plan *create_plan(Query *root, Path *best_path);
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
Index scanrelid, Plan *subplan);
+extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
extern Sort *make_sort(List *tlist, Plan *lefttree, int keycount);
extern Sort *make_sort_from_pathkeys(List *tlist, Plan *lefttree,
List *pathkeys);
@@ -41,7 +42,6 @@ extern Limit *make_limit(List *tlist, Plan *lefttree,
extern SetOp *make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
List *distinctList, AttrNumber flagColIdx);
extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
-extern void copy_plan_costsize(Plan *dest, Plan *src);
/*
* prototypes for plan/initsplan.c
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index 3fc0f435dc3..9467b6485bb 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: planner.h,v 1.17 2000/10/05 19:11:37 tgl Exp $
+ * $Id: planner.h,v 1.18 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,6 @@
extern Plan *planner(Query *parse);
extern Plan *subquery_planner(Query *parse, double tuple_fraction);
-extern Plan *union_planner(Query *parse, double tuple_fraction);
extern Plan *make_sortplan(List *tlist, Plan *plannode, List *sortcls);
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index dcdf6fb62f6..be1811d5871 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: prep.h,v 1.24 2000/10/05 19:11:37 tgl Exp $
+ * $Id: prep.h,v 1.25 2000/11/12 00:37:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,10 +33,12 @@ extern List *preprocess_targetlist(List *tlist, int command_type,
* prototypes for prepunion.c
*/
extern Plan *plan_set_operations(Query *parse);
+
extern List *find_all_inheritors(Oid parentrel);
-extern bool find_inheritable_rt_entry(List *rangetable,
- Index *rt_index, List **inheritors);
-extern Plan *plan_inherit_queries(Query *root, List *tlist,
- Index rt_index, List *inheritors);
+extern List *expand_inherted_rtentry(Query *parse, Index rti);
+
+extern Node *adjust_inherited_attrs(Node *node,
+ Index old_rt_index, Oid old_relid,
+ Index new_rt_index, Oid new_relid);
#endif /* PREP_H */