aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c376
1 files changed, 212 insertions, 164 deletions
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);
}