0002-postpone-rowmark-relation-access.patch
text/x-diff
Filename: 0002-postpone-rowmark-relation-access.patch
Type: text/x-diff
Part: 1
Message:
Re: executor relation handling
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| src/backend/executor/execMain.c | 20 | 32 |
| src/backend/executor/nodeLockRows.c | 15 | 7 |
| src/include/executor/executor.h | 1 | 0 |
| src/include/nodes/execnodes.h | 16 | 12 |
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0a766ef..1775e77 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -919,7 +919,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
Oid relid;
- Relation relation;
ExecRowMark *erm;
/* ignore "parent" rowmarks; they are irrelevant at runtime */
@@ -929,32 +928,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* get relation's OID (will produce InvalidOid if subquery) */
relid = exec_rt_fetch(rc->rti, estate)->relid;
- /* open relation, if we need to access it for this mark type */
- switch (rc->markType)
- {
- case ROW_MARK_EXCLUSIVE:
- case ROW_MARK_NOKEYEXCLUSIVE:
- case ROW_MARK_SHARE:
- case ROW_MARK_KEYSHARE:
- case ROW_MARK_REFERENCE:
- relation = ExecGetRangeTableRelation(estate, rc->rti);
- break;
- case ROW_MARK_COPY:
- /* no physical table access is required */
- relation = NULL;
- break;
- default:
- elog(ERROR, "unrecognized markType: %d", rc->markType);
- relation = NULL; /* keep compiler quiet */
- break;
- }
-
- /* Check that relation is a legal target for marking */
- if (relation)
- CheckValidRowMarkRel(relation, rc->markType);
-
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
- erm->relation = relation;
erm->relid = relid;
erm->rti = rc->rti;
erm->prti = rc->prti;
@@ -963,6 +937,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
erm->strength = rc->strength;
erm->waitPolicy = rc->waitPolicy;
erm->ermActive = false;
+ erm->ermChecked = false;
ItemPointerSetInvalid(&(erm->curCtid));
erm->ermExtra = NULL;
@@ -2462,6 +2437,20 @@ ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
return aerm;
}
+Relation
+ExecRowMarkGetRelation(EState *estate, ExecRowMark *erm)
+{
+ Relation relation = ExecGetRangeTableRelation(estate, erm->rti);
+
+ /* Check that relation is a legal target for marking, if we haven't */
+ if (!erm->ermChecked)
+ {
+ CheckValidRowMarkRel(relation, erm->markType);
+ erm->ermChecked = true;
+ }
+ return relation;
+}
+
/*
* EvalPlanQual logic --- recheck modified tuple(s) to see if we want to
@@ -2935,10 +2924,9 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
if (erm->markType == ROW_MARK_REFERENCE)
{
+ Relation relation = ExecRowMarkGetRelation(epqstate->estate, erm);
HeapTuple copyTuple;
- Assert(erm->relation != NULL);
-
/* fetch the tuple's ctid */
datum = ExecGetJunkAttribute(epqstate->origslot,
aerm->ctidAttNo,
@@ -2948,18 +2936,18 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
continue;
/* fetch requests on foreign tables must be passed to their FDW */
- if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
FdwRoutine *fdwroutine;
bool updated = false;
- fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
+ fdwroutine = GetFdwRoutineForRelation(relation, false);
/* this should have been checked already, but let's be safe */
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
- RelationGetRelationName(erm->relation))));
+ RelationGetRelationName(relation))));
copyTuple = fdwroutine->RefetchForeignRow(epqstate->estate,
erm,
datum,
@@ -2979,7 +2967,7 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
Buffer buffer;
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
- if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
+ if (!heap_fetch(relation, SnapshotAny, &tuple, &buffer,
false, NULL))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index 6db345a..4e161c0 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -74,6 +74,7 @@ lnext:
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
+ Relation relation;
HeapTuple *testTuple;
Datum datum;
bool isNull;
@@ -122,19 +123,22 @@ lnext:
if (isNull)
elog(ERROR, "ctid is NULL");
+ /* access the tuple's relation */
+ relation = ExecRowMarkGetRelation(estate, erm);
+
/* requests for foreign tables must be passed to their FDW */
- if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
FdwRoutine *fdwroutine;
bool updated = false;
- fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
+ fdwroutine = GetFdwRoutineForRelation(relation, false);
/* this should have been checked already, but let's be safe */
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
- RelationGetRelationName(erm->relation))));
+ RelationGetRelationName(relation))));
copyTuple = fdwroutine->RefetchForeignRow(estate,
erm,
datum,
@@ -180,7 +184,7 @@ lnext:
break;
}
- test = heap_lock_tuple(erm->relation, &tuple,
+ test = heap_lock_tuple(relation, &tuple,
estate->es_output_cid,
lockmode, erm->waitPolicy, true,
&buffer, &hufd);
@@ -230,7 +234,7 @@ lnext:
}
/* updated, so fetch and lock the updated version */
- copyTuple = EvalPlanQualFetch(estate, erm->relation,
+ copyTuple = EvalPlanQualFetch(estate, relation,
lockmode, erm->waitPolicy,
&hufd.ctid, hufd.xmax);
@@ -286,6 +290,7 @@ lnext:
{
ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
ExecRowMark *erm = aerm->rowmark;
+ Relation relation;
HeapTupleData tuple;
Buffer buffer;
@@ -309,13 +314,16 @@ lnext:
continue;
}
+ /* access the tuple's relation */
+ relation = ExecRowMarkGetRelation(estate, erm);
+
/* foreign tables should have been fetched above */
- Assert(erm->relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
+ Assert(relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
Assert(ItemPointerIsValid(&(erm->curCtid)));
/* okay, fetch the tuple */
tuple.t_self = erm->curCtid;
- if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
+ if (!heap_fetch(relation, SnapshotAny, &tuple, &buffer,
false, NULL))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index c9ed198..4dbbb3b 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -190,6 +190,7 @@ extern void ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
extern LockTupleMode ExecUpdateLockMode(EState *estate, ResultRelInfo *relinfo);
extern ExecRowMark *ExecFindRowMark(EState *estate, Index rti, bool missing_ok);
extern ExecAuxRowMark *ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist);
+extern Relation ExecRowMarkGetRelation(EState *estate, ExecRowMark *erm);
extern TupleTableSlot *EvalPlanQual(EState *estate, EPQState *epqstate,
Relation relation, Index rti, int lockmode,
ItemPointer tid, TransactionId priorXmax);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 8347089..e2cd7ea 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -597,16 +597,20 @@ typedef struct EState
* ExecRowMark -
* runtime representation of FOR [KEY] UPDATE/SHARE clauses
*
- * When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we will have an
- * ExecRowMark for each non-target relation in the query (except inheritance
- * parent RTEs, which can be ignored at runtime). Virtual relations such as
- * subqueries-in-FROM will have an ExecRowMark with relation == NULL. See
- * PlanRowMark for details about most of the fields. In addition to fields
- * directly derived from PlanRowMark, we store an activity flag (to denote
- * inactive children of inheritance trees), curCtid, which is used by the
- * WHERE CURRENT OF code, and ermExtra, which is available for use by the plan
- * node that sources the relation (e.g., for a foreign table the FDW can use
- * ermExtra to hold information).
+ * When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we will have
+ * an ExecRowMark for each non-target relation in the query (except
+ * inheritance parent RTEs, which can be ignored at runtime). See PlanRowMark
+ * for details about most of the fields. In addition to fields directly
+ * derived from PlanRowMark, we store an activity flag (to denote inactive
+ * children of inheritance trees); a "checked" flag (to denote whether we've
+ * verified the relation is of appropriate type to be marked); curCtid, which
+ * is used by the WHERE CURRENT OF code; and ermExtra, which is available for
+ * use by the plan node that sources the relation (e.g., for a foreign table
+ * the FDW can use ermExtra to hold information).
+ *
+ * For performance reasons, we don't open or verify the relkind of tables
+ * that are never accessed in a query; this is important in partitioned
+ * tables with many partitions. Use ExecRowMarkGetRelation to do that.
*
* EState->es_rowmarks is an array of these structs, indexed by RT index,
* with NULLs for irrelevant RT indexes. es_rowmarks itself is NULL if
@@ -614,8 +618,7 @@ typedef struct EState
*/
typedef struct ExecRowMark
{
- Relation relation; /* opened and suitably locked relation */
- Oid relid; /* its OID (or InvalidOid, if subquery) */
+ Oid relid; /* relation's OID (InvalidOid if subquery) */
Index rti; /* its range table index */
Index prti; /* parent range table index, if child */
Index rowmarkId; /* unique identifier for resjunk columns */
@@ -623,6 +626,7 @@ typedef struct ExecRowMark
LockClauseStrength strength; /* LockingClause's strength, or LCS_NONE */
LockWaitPolicy waitPolicy; /* NOWAIT and SKIP LOCKED */
bool ermActive; /* is this mark relevant for current tuple? */
+ bool ermChecked; /* have we verified relation's relkind? */
ItemPointerData curCtid; /* ctid of currently locked tuple, if any */
void *ermExtra; /* available for use by relation source node */
} ExecRowMark;