ReleaseConnection(dmstate->conn);
dmstate->conn = NULL;
- /* close the target relation. */
- if (dmstate->resultRel)
- ExecCloseScanRelation(dmstate->resultRel);
-
/* MemoryContext will be deleted automatically. */
}
ResultRelInfo *resultRelInfo;
resultRelInfo = makeNode(ResultRelInfo);
- resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
+ resultRelInfo->ri_RangeTableIndex = 0; /* dummy */
resultRelInfo->ri_RelationDesc = heapRel;
resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
resultRelInfo = makeNode(ResultRelInfo);
InitResultRelInfo(resultRelInfo,
cstate->rel,
- 1, /* dummy rangetable index */
+ 1, /* must match rel's position in range_table */
NULL,
0);
target_resultRelInfo = resultRelInfo;
estate->es_num_result_relations = 1;
estate->es_result_relation_info = resultRelInfo;
estate->es_range_table = cstate->range_table;
+ estate->es_relations = (Relation *) palloc0(list_length(cstate->range_table) *
+ sizeof(Relation));
/* Set up a tuple slot too */
myslot = ExecInitExtraTupleSlot(estate, tupDesc);
* initialize the node's execution state
*/
estate->es_range_table = rangeTable;
+
+ /*
+ * Allocate an array to store an open Relation corresponding to each
+ * rangeTable item, and initialize entries to NULL. Relations are opened
+ * and stored here as needed.
+ */
+ estate->es_relations = (Relation *) palloc0(list_length(rangeTable) *
+ sizeof(Relation));
+
estate->es_plannedstmt = plannedstmt;
/*
foreach(l, resultRelations)
{
Index resultRelationIndex = lfirst_int(l);
- Oid resultRelationOid;
Relation resultRelation;
- resultRelationOid = getrelid(resultRelationIndex, rangeTable);
- resultRelation = heap_open(resultRelationOid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelation, RowExclusiveLock, true));
-
+ resultRelation = ExecGetRangeTableRelation(estate,
+ resultRelationIndex);
InitResultRelInfo(resultRelInfo,
resultRelation,
resultRelationIndex,
foreach(l, plannedstmt->rootResultRelations)
{
Index resultRelIndex = lfirst_int(l);
- Oid resultRelOid;
Relation resultRelDesc;
- resultRelOid = getrelid(resultRelIndex, rangeTable);
- resultRelDesc = heap_open(resultRelOid, NoLock);
- Assert(CheckRelationLockedByMe(resultRelDesc, RowExclusiveLock, true));
+ resultRelDesc = ExecGetRangeTableRelation(estate,
+ resultRelIndex);
InitResultRelInfo(resultRelInfo,
resultRelDesc,
- lfirst_int(l),
+ resultRelIndex,
NULL,
estate->es_instrument);
resultRelInfo++;
case ROW_MARK_SHARE:
case ROW_MARK_KEYSHARE:
case ROW_MARK_REFERENCE:
- relation = heap_open(relid, NoLock);
- Assert(CheckRelationLockedByMe(relation,
- rt_fetch(rc->rti, rangeTable)->rellockmode,
- true));
+ relation = ExecGetRangeTableRelation(estate, rc->rti);
break;
case ROW_MARK_COPY:
/* no physical table access is required */
{
ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
- /* Close indices and then the relation itself */
- ExecCloseIndices(resultRelInfo);
+ /*
+ * Assert this is a "dummy" ResultRelInfo, see above. Otherwise we
+ * might be issuing a duplicate close against a Relation opened by
+ * ExecGetRangeTableRelation.
+ */
+ Assert(resultRelInfo->ri_RangeTableIndex == 0);
+
+ /*
+ * Since ExecGetTriggerResultRel doesn't call ExecOpenIndices for
+ * these rels, we needn't call ExecCloseIndices either.
+ */
+ Assert(resultRelInfo->ri_NumIndices == 0);
+
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
}
}
ExecEndPlan(PlanState *planstate, EState *estate)
{
ResultRelInfo *resultRelInfo;
+ int num_relations;
int i;
ListCell *l;
ExecResetTupleTable(estate->es_tupleTable, false);
/*
- * close the result relation(s) if any, but hold locks until xact commit.
+ * close indexes of result relation(s) if any. (Rels themselves get
+ * closed next.)
*/
resultRelInfo = estate->es_result_relations;
for (i = estate->es_num_result_relations; i > 0; i--)
{
- /* Close indices and then the relation itself */
ExecCloseIndices(resultRelInfo);
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
resultRelInfo++;
}
- /* Close the root target relation(s). */
- resultRelInfo = estate->es_root_result_relations;
- for (i = estate->es_num_root_result_relations; i > 0; i--)
+ /*
+ * close whatever rangetable Relations have been opened. We did not
+ * acquire locks in ExecGetRangeTableRelation, so don't release 'em here.
+ */
+ num_relations = list_length(estate->es_range_table);
+ for (i = 0; i < num_relations; i++)
{
- heap_close(resultRelInfo->ri_RelationDesc, NoLock);
- resultRelInfo++;
+ if (estate->es_relations[i])
+ heap_close(estate->es_relations[i], NoLock);
}
/* likewise close any trigger target relations */
ExecCleanUpTriggerState(estate);
-
- /*
- * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping
- * locks
- */
- foreach(l, estate->es_rowMarks)
- {
- ExecRowMark *erm = (ExecRowMark *) lfirst(l);
-
- if (erm->relation)
- heap_close(erm->relation, NoLock);
- }
}
/* ----------------------------------------------------------------
estate->es_snapshot = parentestate->es_snapshot;
estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
estate->es_range_table = parentestate->es_range_table;
+ estate->es_relations = parentestate->es_relations;
estate->es_plannedstmt = parentestate->es_plannedstmt;
estate->es_junkFilter = parentestate->es_junkFilter;
estate->es_output_cid = parentestate->es_output_cid;
ExprContext *ecxt = GetPerTupleExprContext(estate);
TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
TupleTableSlot *myslot = NULL;
- MemoryContext oldcxt;
+ MemoryContext oldcxt;
/* use per-tuple context here to avoid leaking memory */
oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
* functions. Details stored include how to map the partition index
* returned by the partition pruning code into subplan indexes.
*
- * ExecDestroyPartitionPruneState:
- * Deletes a PartitionPruneState. Must be called during executor shutdown.
- *
* ExecFindInitialMatchingSubPlans:
* Returns indexes of matching subplans. Partition pruning is attempted
* without any evaluation of expressions containing PARAM_EXEC Params.
ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo)
{
+ EState *estate = planstate->state;
PartitionPruneState *prunestate;
int n_part_hierarchies;
ListCell *lc;
PartitionedRelPruneInfo *pinfo = lfirst_node(PartitionedRelPruneInfo, lc2);
PartitionedRelPruningData *pprune = &prunedata->partrelprunedata[j];
PartitionPruneContext *context = &pprune->context;
+ Relation partrel;
PartitionDesc partdesc;
PartitionKey partkey;
int partnatts;
pprune->present_parts = bms_copy(pinfo->present_parts);
/*
- * We need to hold a pin on the partitioned table's relcache entry
- * so that we can rely on its copies of the table's partition key
- * and partition descriptor. We need not get a lock though; one
- * should have been acquired already by InitPlan or
- * ExecLockNonLeafAppendTables.
+ * We can rely on the copies of the partitioned table's partition
+ * key and partition descriptor appearing in its relcache entry,
+ * because that entry will be held open and locked for the
+ * duration of this executor run.
*/
- context->partrel = relation_open(pinfo->reloid, NoLock);
+ partrel = ExecGetRangeTableRelation(estate, pinfo->rtindex);
+ partkey = RelationGetPartitionKey(partrel);
+ partdesc = RelationGetPartitionDesc(partrel);
- partkey = RelationGetPartitionKey(context->partrel);
- partdesc = RelationGetPartitionDesc(context->partrel);
n_steps = list_length(pinfo->pruning_steps);
context->strategy = partkey->strategy;
return prunestate;
}
-/*
- * ExecDestroyPartitionPruneState
- * Release resources at plan shutdown.
- *
- * We don't bother to free any memory here, since the whole executor context
- * will be going away shortly. We do need to release our relcache pins.
- */
-void
-ExecDestroyPartitionPruneState(PartitionPruneState *prunestate)
-{
- PartitionPruningData **partprunedata = prunestate->partprunedata;
- int i;
-
- for (i = 0; i < prunestate->num_partprunedata; i++)
- {
- PartitionPruningData *prunedata = partprunedata[i];
- PartitionedRelPruningData *pprune = prunedata->partrelprunedata;
- int j;
-
- for (j = 0; j < prunedata->num_partrelprunedata; j++)
- relation_close(pprune[j].context.partrel, NoLock);
- }
-}
-
/*
* ExecFindInitialMatchingSubPlans
* Identify the set of subplans that cannot be eliminated by initial
* etc
*
* ExecOpenScanRelation Common code for scan node init routines.
- * ExecCloseScanRelation
+ *
+ * ExecGetRangeTableRelation Fetch Relation for a rangetable entry.
*
* executor_errposition Report syntactic position of an error.
*
estate->es_snapshot = InvalidSnapshot; /* caller must initialize this */
estate->es_crosscheck_snapshot = InvalidSnapshot; /* no crosscheck */
estate->es_range_table = NIL;
+ estate->es_relations = NULL;
estate->es_plannedstmt = NULL;
estate->es_junkFilter = NULL;
ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
{
Relation rel;
- Oid reloid;
- /* Open the relation and verify lock was obtained upstream */
- reloid = getrelid(scanrelid, estate->es_range_table);
- rel = heap_open(reloid, NoLock);
- Assert(IsParallelWorker() ||
- CheckRelationLockedByMe(rel,
- rt_fetch(scanrelid, estate->es_range_table)->rellockmode,
- true));
+ /* Open the relation. */
+ rel = ExecGetRangeTableRelation(estate, scanrelid);
/*
* Complain if we're attempting a scan of an unscannable relation, except
return rel;
}
-/* ----------------------------------------------------------------
- * ExecCloseScanRelation
- *
- * Close the heap relation scanned by a base-level scan plan node.
- * This should be called during the node's ExecEnd routine.
- *
- * Currently, we do not release the lock acquired by ExecOpenScanRelation.
- * This lock should be held till end of transaction. (There is a faction
- * that considers this too much locking, however.)
+/*
+ * ExecGetRangeTableRelation
+ * Open the Relation for a range table entry, if not already done
*
- * If we did want to release the lock, we'd have to repeat the logic in
- * ExecOpenScanRelation in order to figure out what to release.
- * ----------------------------------------------------------------
+ * The Relations will be closed again in ExecEndPlan().
*/
-void
-ExecCloseScanRelation(Relation scanrel)
+Relation
+ExecGetRangeTableRelation(EState *estate, Index rti)
{
- heap_close(scanrel, NoLock);
+ Relation rel;
+
+ Assert(rti > 0 && rti <= list_length(estate->es_range_table));
+
+ rel = estate->es_relations[rti - 1];
+ if (rel == NULL)
+ {
+ /* First time through, so open the relation */
+ RangeTblEntry *rte = rt_fetch(rti, estate->es_range_table);
+
+ Assert(rte->rtekind == RTE_RELATION);
+
+ rel = estate->es_relations[rti - 1] = heap_open(rte->relid, NoLock);
+
+ /*
+ * Verify that appropriate lock was obtained before execution.
+ *
+ * In the case of parallel query, only the leader would've obtained
+ * the lock (that needs to be fixed, though).
+ */
+ Assert(IsParallelWorker() ||
+ CheckRelationLockedByMe(rel, rte->rellockmode, false));
+ }
+
+ return rel;
}
/*
*/
for (i = 0; i < nplans; i++)
ExecEndNode(appendplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->as_prune_state)
- ExecDestroyPartitionPruneState(node->as_prune_state);
}
void
void
ExecEndBitmapHeapScan(BitmapHeapScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* extract information from the node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
* close heap scan
*/
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
/* Clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* Close the heap relation */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
void
/* clean out the tuple table */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /* close the relation. */
- if (node->ss.ss_currentRelation)
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->ioss_RelationDesc;
indexScanDesc = node->ioss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/* Release VM buffer pin, if any. */
if (node->ioss_VMBuffer != InvalidBuffer)
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
* Note: we pass 'false' because tuples returned by amgetnext are
* pointers onto disk pages and must not be pfree()'d.
*/
- ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+ ExecStoreBufferHeapTuple(tuple, /* tuple to store */
slot, /* slot to store in */
scandesc->xs_cbuf); /* buffer containing
* tuple */
/*
* Store the scanned tuple in the scan tuple slot of the scan state.
*/
- ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+ ExecStoreBufferHeapTuple(tuple, /* tuple to store */
slot, /* slot to store in */
scandesc->xs_cbuf); /* buffer containing
* tuple */
{
Relation indexRelationDesc;
IndexScanDesc indexScanDesc;
- Relation relation;
/*
* extract information from the node
*/
indexRelationDesc = node->iss_RelationDesc;
indexScanDesc = node->iss_ScanDesc;
- relation = node->ss.ss_currentRelation;
/*
* Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
index_endscan(indexScanDesc);
if (indexRelationDesc)
index_close(indexRelationDesc, NoLock);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
*/
for (i = 0; i < nplans; i++)
ExecEndNode(mergeplans[i]);
-
- /*
- * release any resources associated with run-time pruning
- */
- if (node->ms_prune_state)
- ExecDestroyPartitionPruneState(node->ms_prune_state);
}
void
slot = node->ss.ss_ScanTupleSlot;
if (tuple)
- ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+ ExecStoreBufferHeapTuple(tuple, /* tuple to store */
slot, /* slot to store in */
- node->ss.ss_currentScanDesc->rs_cbuf); /* tuple's buffer */
+ node->ss.ss_currentScanDesc->rs_cbuf); /* tuple's buffer */
else
ExecClearTuple(slot);
*/
if (node->ss.ss_currentScanDesc)
heap_endscan(node->ss.ss_currentScanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
* refcount will not be dropped until the tuple table slot is cleared.
*/
if (tuple)
- ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+ ExecStoreBufferHeapTuple(tuple, /* tuple to store */
slot, /* slot to store in */
scandesc->rs_cbuf); /* buffer associated
* with this tuple */
void
ExecEndSeqScan(SeqScanState *node)
{
- Relation relation;
HeapScanDesc scanDesc;
/*
* get information from node
*/
- relation = node->ss.ss_currentRelation;
scanDesc = node->ss.ss_currentScanDesc;
/*
*/
if (scanDesc != NULL)
heap_endscan(scanDesc);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(relation);
}
/* ----------------------------------------------------------------
* Store the scanned tuple in the scan tuple slot of the scan
* state. Eventually we will only do this and not return a tuple.
*/
- ExecStoreBufferHeapTuple(tuple, /* tuple to store */
+ ExecStoreBufferHeapTuple(tuple, /* tuple to store */
slot, /* slot to store in */
buffer); /* buffer associated with
* tuple */
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
-
- /*
- * close the heap relation.
- */
- ExecCloseScanRelation(node->ss.ss_currentRelation);
}
/* ----------------------------------------------------------------
{
PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo);
- COPY_SCALAR_FIELD(reloid);
+ COPY_SCALAR_FIELD(rtindex);
COPY_NODE_FIELD(pruning_steps);
COPY_BITMAPSET_FIELD(present_parts);
COPY_SCALAR_FIELD(nparts);
WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO");
- WRITE_OID_FIELD(reloid);
+ WRITE_UINT_FIELD(rtindex);
WRITE_NODE_FIELD(pruning_steps);
WRITE_BITMAPSET_FIELD(present_parts);
WRITE_INT_FIELD(nparts);
{
READ_LOCALS(PartitionedRelPruneInfo);
- READ_OID_FIELD(reloid);
+ READ_UINT_FIELD(rtindex);
READ_NODE_FIELD(pruning_steps);
READ_BITMAPSET_FIELD(present_parts);
READ_INT_FIELD(nparts);
(Plan *) lfirst(l),
rtoffset);
}
+ if (splan->part_prune_info)
+ {
+ foreach(l, splan->part_prune_info->prune_infos)
+ {
+ List *prune_infos = lfirst(l);
+ ListCell *l2;
+
+ foreach(l2, prune_infos)
+ {
+ PartitionedRelPruneInfo *pinfo = lfirst(l2);
+
+ pinfo->rtindex += rtoffset;
+ }
+ }
+ }
}
break;
case T_MergeAppend:
(Plan *) lfirst(l),
rtoffset);
}
+ if (splan->part_prune_info)
+ {
+ foreach(l, splan->part_prune_info->prune_infos)
+ {
+ List *prune_infos = lfirst(l);
+ ListCell *l2;
+
+ foreach(l2, prune_infos)
+ {
+ PartitionedRelPruneInfo *pinfo = lfirst(l2);
+
+ pinfo->rtindex += rtoffset;
+ }
+ }
+ }
}
break;
case T_RecursiveUnion:
Index rti = lfirst_int(lc);
RelOptInfo *subpart = find_base_rel(root, rti);
PartitionedRelPruneInfo *pinfo;
- RangeTblEntry *rte;
Bitmapset *present_parts;
int nparts = subpart->nparts;
int partnatts = subpart->part_scheme->partnatts;
present_parts = bms_add_member(present_parts, i);
}
- rte = root->simple_rte_array[subpart->relid];
-
pinfo = makeNode(PartitionedRelPruneInfo);
- pinfo->reloid = rte->relid;
+ pinfo->rtindex = rti;
pinfo->pruning_steps = pruning_steps;
pinfo->present_parts = present_parts;
pinfo->nparts = nparts;
context.ppccontext = CurrentMemoryContext;
/* These are not valid when being called from the planner */
- context.partrel = NULL;
context.planstate = NULL;
context.exprstates = NULL;
context.exprhasexecparam = NULL;
rte->relkind = rel->localrel->rd_rel->relkind;
rte->rellockmode = AccessShareLock;
estate->es_range_table = list_make1(rte);
+ estate->es_relations = (Relation *) palloc0(1 * sizeof(Relation));
resultRelInfo = makeNode(ResultRelInfo);
InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
PartitionTupleRouting *proute);
extern PartitionPruneState *ExecCreatePartitionPruneState(PlanState *planstate,
PartitionPruneInfo *partitionpruneinfo);
-extern void ExecDestroyPartitionPruneState(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindMatchingSubPlans(PartitionPruneState *prunestate);
extern Bitmapset *ExecFindInitialMatchingSubPlans(PartitionPruneState *prunestate,
int nsubplans);
extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
extern Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags);
-extern void ExecCloseScanRelation(Relation scanrel);
+
+extern Relation ExecGetRangeTableRelation(EState *estate, Index rti);
extern int executor_errposition(EState *estate, int location);
* Whenever we update an existing relation, we have to update indexes on the
* relation, and perhaps also fire triggers. ResultRelInfo holds all the
* information needed about a result relation, including indexes.
+ *
+ * Normally, a ResultRelInfo refers to a table that is in the query's
+ * range table; then ri_RangeTableIndex is the RT index and ri_RelationDesc
+ * is just a copy of the relevant es_relations[] entry. But sometimes,
+ * in ResultRelInfos used only for triggers, ri_RangeTableIndex is zero
+ * and ri_RelationDesc is a separately-opened relcache pointer that needs
+ * to be separately closed. See ExecGetTriggerResultRel.
*/
typedef struct ResultRelInfo
{
NodeTag type;
- /* result relation's range table index */
+ /* result relation's range table index, or 0 if not in range table */
Index ri_RangeTableIndex;
/* relation descriptor for result relation */
Snapshot es_snapshot; /* time qual to use */
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
List *es_range_table; /* List of RangeTblEntry */
+ Relation *es_relations; /* Array of per-es_range_table-entry Relation
+ * pointers, or NULL if not yet opened */
PlannedStmt *es_plannedstmt; /* link to top of plan tree */
const char *es_sourceText; /* Source text from QueryDesc */
typedef struct PartitionedRelPruneInfo
{
NodeTag type;
- Oid reloid; /* OID of partition rel for this level */
+ Index rtindex; /* RT index of partition rel for this level */
List *pruning_steps; /* List of PartitionPruneStep, see below */
Bitmapset *present_parts; /* Indexes of all partitions which subplans or
* subparts are present for. */
* Stores information needed at runtime for pruning computations
* related to a single partitioned table.
*
- * partrel Relcache pointer for the partitioned table,
- * if we have it open (else NULL).
* strategy Partition strategy, e.g. LIST, RANGE, HASH.
* partnatts Number of columns in the partition key.
* nparts Number of partitions in this partitioned table.
*/
typedef struct PartitionPruneContext
{
- Relation partrel;
char strategy;
int partnatts;
int nparts;