Commit 6543d81d authored by Tom Lane's avatar Tom Lane

Restructure handling of inheritance queries so that they work with outer

joins, and clean things up a good deal at the same time.  Append plan node
no longer hacks on rangetable at runtime --- instead, all child tables are
given their own RT entries during planning.  Concept of multiple target
tables pushed up into execMain, replacing bug-prone implementation within
nodeAppend.  Planner now supports generating Append plans for inheritance
sets either at the top of the plan (the old way) or at the bottom.  Expanding
at the bottom is appropriate for tables used as sources, since they may
appear inside an outer join; but we must still expand at the top when the
target of an UPDATE or DELETE is an inheritance set, because we actually need
a different targetlist and junkfilter for each target table in that case.
Fortunately a target table can't be inside an outer join...  Bizarre mutual
recursion between union_planner and prepunion.c is gone --- in fact,
union_planner doesn't really have much to do with union queries anymore,
so I renamed it grouping_planner.
parent 609f9199
......@@ -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);
......
......@@ -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);
}
......
......@@ -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))
......
This diff is collapsed.
......@@ -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);
......
......@@ -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:
{
......
......@@ -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);
/*
......
......@@ -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;
}
......
......@@ -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)
{
......
......@@ -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 */
......
......@@ -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;
}
......@@ -1275,6 +1274,30 @@ _copyTidPath(TidPath *from)
return newnode;
}
/* ----------------
* _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
*
......@@ -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;
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -435,6 +435,16 @@ _equalTidPath(TidPath *a, TidPath *b)
return true;
}
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)
{
......@@ -555,28 +565,6 @@ _equalStream(Stream *a, Stream *b)
return equal(a->downstream, b->downstream);
}
/*
* 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;
......
......@@ -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");
}
/*
......@@ -945,25 +948,6 @@ _outJoinExpr(StringInfo str, JoinExpr *node)
_outNode(str, node->colvars);
}
/*
* 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,10 +1091,27 @@ _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
*/
......@@ -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;
......
......@@ -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;
}
......@@ -1297,43 +1288,6 @@ _readJoinExpr(void)
return local_node;
}
/*
* 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
*/
......@@ -1639,6 +1593,42 @@ _readTidPath(void)
return local_node;
}
/* ----------------
* _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
*
......@@ -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)
......
......@@ -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
......
......@@ -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,10 +118,30 @@ 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 */
set_plain_rel_pathlist(root, rel, rte);
}
}
}
/*
* 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);
/* Mark rel with estimated output rows, width, etc */
......@@ -143,13 +172,109 @@ set_base_rel_pathlist(Query *root)
* 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");
/*
* 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.
......
......@@ -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
......
This diff is collapsed.
......@@ -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...)
*/
......
......@@ -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.
......
This diff is collapsed.
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -390,6 +390,37 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
return pathnode;
}
/*
* 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,
......
......@@ -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;
}
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200011110
#define CATALOG_VERSION_NO 200011112
#endif
......@@ -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);
......
......@@ -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;
/* ----------------
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -52,31 +52,6 @@ typedef struct IndexInfo
bool ii_Unique;
} 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
*
......@@ -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;
/*
......@@ -210,6 +183,35 @@ typedef struct JunkFilter
AttrNumber *jf_cleanMap;
} 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
*
......@@ -217,7 +219,7 @@ typedef struct JunkFilter
*
* 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;
/* ----------------------------------------------------------------
......
......@@ -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,
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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;
......@@ -320,6 +331,17 @@ typedef struct TidPath
Relids unjoined_relids;/* some rels not yet part of my Path */
} 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.
*/
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment