PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nodeLockRows.c File Reference
#include "postgres.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "executor/executor.h"
#include "executor/nodeLockRows.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "utils/rel.h"
Include dependency graph for nodeLockRows.c:

Go to the source code of this file.

Functions

static TupleTableSlotExecLockRows (PlanState *pstate)
 
LockRowsStateExecInitLockRows (LockRows *node, EState *estate, int eflags)
 
void ExecEndLockRows (LockRowsState *node)
 
void ExecReScanLockRows (LockRowsState *node)
 

Function Documentation

◆ ExecEndLockRows()

void ExecEndLockRows ( LockRowsState node)

Definition at line 385 of file nodeLockRows.c.

386{
387 /* We may have shut down EPQ already, but no harm in another call */
390}
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:2991
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
#define outerPlanState(node)
Definition: execnodes.h:1221
EPQState lr_epqstate
Definition: execnodes.h:2849

References EvalPlanQualEnd(), ExecEndNode(), LockRowsState::lr_epqstate, and outerPlanState.

Referenced by ExecEndNode().

◆ ExecInitLockRows()

LockRowsState * ExecInitLockRows ( LockRows node,
EState estate,
int  eflags 
)

Definition at line 291 of file nodeLockRows.c.

292{
293 LockRowsState *lrstate;
294 Plan *outerPlan = outerPlan(node);
295 List *epq_arowmarks;
296 ListCell *lc;
297
298 /* check for unsupported flags */
299 Assert(!(eflags & EXEC_FLAG_MARK));
300
301 /*
302 * create state structure
303 */
304 lrstate = makeNode(LockRowsState);
305 lrstate->ps.plan = (Plan *) node;
306 lrstate->ps.state = estate;
307 lrstate->ps.ExecProcNode = ExecLockRows;
308
309 /*
310 * Miscellaneous initialization
311 *
312 * LockRows nodes never call ExecQual or ExecProject, therefore no
313 * ExprContext is needed.
314 */
315
316 /*
317 * Initialize result type.
318 */
319 ExecInitResultTypeTL(&lrstate->ps);
320
321 /*
322 * then initialize outer plan
323 */
324 outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
325
326 /* node returns unmodified slots from the outer plan */
327 lrstate->ps.resultopsset = true;
329 &lrstate->ps.resultopsfixed);
330
331 /*
332 * LockRows nodes do no projections, so initialize projection info for
333 * this node appropriately
334 */
335 lrstate->ps.ps_ProjInfo = NULL;
336
337 /*
338 * Locate the ExecRowMark(s) that this node is responsible for, and
339 * construct ExecAuxRowMarks for them. (InitPlan should already have
340 * built the global list of ExecRowMarks.)
341 */
342 lrstate->lr_arowMarks = NIL;
343 epq_arowmarks = NIL;
344 foreach(lc, node->rowMarks)
345 {
347 ExecRowMark *erm;
348 ExecAuxRowMark *aerm;
349
350 /* ignore "parent" rowmarks; they are irrelevant at runtime */
351 if (rc->isParent)
352 continue;
353
354 /* find ExecRowMark and build ExecAuxRowMark */
355 erm = ExecFindRowMark(estate, rc->rti, false);
356 aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
357
358 /*
359 * Only locking rowmarks go into our own list. Non-locking marks are
360 * passed off to the EvalPlanQual machinery. This is because we don't
361 * want to bother fetching non-locked rows unless we actually have to
362 * do an EPQ recheck.
363 */
365 lrstate->lr_arowMarks = lappend(lrstate->lr_arowMarks, aerm);
366 else
367 epq_arowmarks = lappend(epq_arowmarks, aerm);
368 }
369
370 /* Now we have the info needed to set up EPQ state */
371 EvalPlanQualInit(&lrstate->lr_epqstate, estate,
372 outerPlan, epq_arowmarks, node->epqParam, NIL);
373
374 return lrstate;
375}
#define Assert(condition)
Definition: c.h:812
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2386
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2409
void EvalPlanQualInit(EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
Definition: execMain.c:2548
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1942
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:504
#define EXEC_FLAG_MARK
Definition: executor.h:69
List * lappend(List *list, void *datum)
Definition: list.c:339
static TupleTableSlot * ExecLockRows(PlanState *pstate)
Definition: nodeLockRows.c:38
#define makeNode(_type_)
Definition: nodes.h:155
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define NIL
Definition: pg_list.h:68
#define outerPlan(node)
Definition: plannodes.h:183
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:1335
RowMarkType markType
Definition: execnodes.h:767
Definition: pg_list.h:54
PlanState ps
Definition: execnodes.h:2847
List * lr_arowMarks
Definition: execnodes.h:2848
int epqParam
Definition: plannodes.h:1258
List * rowMarks
Definition: plannodes.h:1257
bool isParent
Definition: plannodes.h:1387
const TupleTableSlotOps * resultops
Definition: execnodes.h:1202
bool resultopsset
Definition: execnodes.h:1210
Plan * plan
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:1127
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1165
bool resultopsfixed
Definition: execnodes.h:1206
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1131

References Assert, LockRows::epqParam, EvalPlanQualInit(), EXEC_FLAG_MARK, ExecBuildAuxRowMark(), ExecFindRowMark(), ExecGetResultSlotOps(), ExecInitNode(), ExecInitResultTypeTL(), ExecLockRows(), PlanState::ExecProcNode, PlanRowMark::isParent, lappend(), lfirst_node, LockRowsState::lr_arowMarks, LockRowsState::lr_epqstate, makeNode, ExecRowMark::markType, NIL, outerPlan, outerPlanState, PlanState::plan, LockRowsState::ps, PlanState::ps_ProjInfo, PlanState::resultops, PlanState::resultopsfixed, PlanState::resultopsset, RowMarkRequiresRowShareLock, LockRows::rowMarks, PlanRowMark::rti, and PlanState::state.

Referenced by ExecInitNode().

◆ ExecLockRows()

static TupleTableSlot * ExecLockRows ( PlanState pstate)
static

Definition at line 38 of file nodeLockRows.c.

39{
40 LockRowsState *node = castNode(LockRowsState, pstate);
41 TupleTableSlot *slot;
42 EState *estate;
44 bool epq_needed;
45 ListCell *lc;
46
48
49 /*
50 * get information from the node
51 */
52 estate = node->ps.state;
54
55 /*
56 * Get next tuple from subplan, if any.
57 */
58lnext:
59 slot = ExecProcNode(outerPlan);
60
61 if (TupIsNull(slot))
62 {
63 /* Release any resources held by EPQ mechanism before exiting */
65 return NULL;
66 }
67
68 /* We don't need EvalPlanQual unless we get updated tuple version(s) */
69 epq_needed = false;
70
71 /*
72 * Attempt to lock the source tuple(s). (Note we only have locking
73 * rowmarks in lr_arowMarks.)
74 */
75 foreach(lc, node->lr_arowMarks)
76 {
77 ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
78 ExecRowMark *erm = aerm->rowmark;
79 Datum datum;
80 bool isNull;
82 TM_FailureData tmfd;
83 LockTupleMode lockmode;
84 int lockflags = 0;
86 TupleTableSlot *markSlot;
87
88 /* clear any leftover test tuple for this rel */
89 markSlot = EvalPlanQualSlot(&node->lr_epqstate, erm->relation, erm->rti);
90 ExecClearTuple(markSlot);
91
92 /* if child rel, must check whether it produced this row */
93 if (erm->rti != erm->prti)
94 {
95 Oid tableoid;
96
97 datum = ExecGetJunkAttribute(slot,
98 aerm->toidAttNo,
99 &isNull);
100 /* shouldn't ever get a null result... */
101 if (isNull)
102 elog(ERROR, "tableoid is NULL");
103 tableoid = DatumGetObjectId(datum);
104
105 Assert(OidIsValid(erm->relid));
106 if (tableoid != erm->relid)
107 {
108 /* this child is inactive right now */
109 erm->ermActive = false;
111 continue;
112 }
113 }
114 erm->ermActive = true;
115
116 /* fetch the tuple's ctid */
117 datum = ExecGetJunkAttribute(slot,
118 aerm->ctidAttNo,
119 &isNull);
120 /* shouldn't ever get a null result... */
121 if (isNull)
122 elog(ERROR, "ctid is NULL");
123
124 /* requests for foreign tables must be passed to their FDW */
125 if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
126 {
127 FdwRoutine *fdwroutine;
128 bool updated = false;
129
130 fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
131 /* this should have been checked already, but let's be safe */
132 if (fdwroutine->RefetchForeignRow == NULL)
134 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
135 errmsg("cannot lock rows in foreign table \"%s\"",
137
138 fdwroutine->RefetchForeignRow(estate,
139 erm,
140 datum,
141 markSlot,
142 &updated);
143 if (TupIsNull(markSlot))
144 {
145 /* couldn't get the lock, so skip this row */
146 goto lnext;
147 }
148
149 /*
150 * if FDW says tuple was updated before getting locked, we need to
151 * perform EPQ testing to see if quals are still satisfied
152 */
153 if (updated)
154 epq_needed = true;
155
156 continue;
157 }
158
159 /* okay, try to lock (and fetch) the tuple */
160 tid = *((ItemPointer) DatumGetPointer(datum));
161 switch (erm->markType)
162 {
164 lockmode = LockTupleExclusive;
165 break;
167 lockmode = LockTupleNoKeyExclusive;
168 break;
169 case ROW_MARK_SHARE:
170 lockmode = LockTupleShare;
171 break;
173 lockmode = LockTupleKeyShare;
174 break;
175 default:
176 elog(ERROR, "unsupported rowmark type");
177 lockmode = LockTupleNoKeyExclusive; /* keep compiler quiet */
178 break;
179 }
180
184
185 test = table_tuple_lock(erm->relation, &tid, estate->es_snapshot,
186 markSlot, estate->es_output_cid,
187 lockmode, erm->waitPolicy,
188 lockflags,
189 &tmfd);
190
191 switch (test)
192 {
193 case TM_WouldBlock:
194 /* couldn't lock tuple in SKIP LOCKED mode */
195 goto lnext;
196
197 case TM_SelfModified:
198
199 /*
200 * The target tuple was already updated or deleted by the
201 * current command, or by a later command in the current
202 * transaction. We *must* ignore the tuple in the former
203 * case, so as to avoid the "Halloween problem" of repeated
204 * update attempts. In the latter case it might be sensible
205 * to fetch the updated tuple instead, but doing so would
206 * require changing heap_update and heap_delete to not
207 * complain about updating "invisible" tuples, which seems
208 * pretty scary (table_tuple_lock will not complain, but few
209 * callers expect TM_Invisible, and we're not one of them). So
210 * for now, treat the tuple as deleted and do not process.
211 */
212 goto lnext;
213
214 case TM_Ok:
215
216 /*
217 * Got the lock successfully, the locked tuple saved in
218 * markSlot for, if needed, EvalPlanQual testing below.
219 */
220 if (tmfd.traversed)
221 epq_needed = true;
222 break;
223
224 case TM_Updated:
228 errmsg("could not serialize access due to concurrent update")));
229 elog(ERROR, "unexpected table_tuple_lock status: %u",
230 test);
231 break;
232
233 case TM_Deleted:
237 errmsg("could not serialize access due to concurrent update")));
238 /* tuple was deleted so don't return it */
239 goto lnext;
240
241 case TM_Invisible:
242 elog(ERROR, "attempted to lock invisible tuple");
243 break;
244
245 default:
246 elog(ERROR, "unrecognized table_tuple_lock status: %u",
247 test);
248 }
249
250 /* Remember locked tuple's TID for EPQ testing and WHERE CURRENT OF */
251 erm->curCtid = tid;
252 }
253
254 /*
255 * If we need to do EvalPlanQual testing, do so.
256 */
257 if (epq_needed)
258 {
259 /* Initialize EPQ machinery */
261
262 /*
263 * To fetch non-locked source rows the EPQ logic needs to access junk
264 * columns from the tuple being tested.
265 */
266 EvalPlanQualSetSlot(&node->lr_epqstate, slot);
267
268 /*
269 * And finally we can re-evaluate the tuple.
270 */
271 slot = EvalPlanQualNext(&node->lr_epqstate);
272 if (TupIsNull(slot))
273 {
274 /* Updated tuple fails qual, so ignore it and go on */
275 goto lnext;
276 }
277 }
278
279 /* Got all locks, so return the current tuple */
280 return slot;
281}
#define OidIsValid(objectId)
Definition: c.h:729
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition: execMain.c:2607
void EvalPlanQualBegin(EPQState *epqstate)
Definition: execMain.c:2760
TupleTableSlot * EvalPlanQualNext(EPQState *epqstate)
Definition: execMain.c:2744
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:267
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:242
static Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: executor.h:184
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:442
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
ItemPointerData * ItemPointer
Definition: itemptr.h:49
LockTupleMode
Definition: lockoptions.h:50
@ LockTupleExclusive
Definition: lockoptions.h:58
@ LockTupleNoKeyExclusive
Definition: lockoptions.h:56
@ LockTupleShare
Definition: lockoptions.h:54
@ LockTupleKeyShare
Definition: lockoptions.h:52
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
#define lfirst(lc)
Definition: pg_list.h:172
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76
@ ROW_MARK_SHARE
Definition: plannodes.h:1329
@ ROW_MARK_EXCLUSIVE
Definition: plannodes.h:1327
@ ROW_MARK_NOKEYEXCLUSIVE
Definition: plannodes.h:1328
@ ROW_MARK_KEYSHARE
Definition: plannodes.h:1330
uintptr_t Datum
Definition: postgres.h:64
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
unsigned int Oid
Definition: postgres_ext.h:31
static void test(void)
#define RelationGetRelationName(relation)
Definition: rel.h:539
CommandId es_output_cid
Definition: execnodes.h:647
Snapshot es_snapshot
Definition: execnodes.h:632
ExecRowMark * rowmark
Definition: execnodes.h:786
AttrNumber toidAttNo
Definition: execnodes.h:788
AttrNumber ctidAttNo
Definition: execnodes.h:787
ItemPointerData curCtid
Definition: execnodes.h:771
Index rti
Definition: execnodes.h:764
bool ermActive
Definition: execnodes.h:770
Index prti
Definition: execnodes.h:765
Relation relation
Definition: execnodes.h:762
LockWaitPolicy waitPolicy
Definition: execnodes.h:769
RefetchForeignRow_function RefetchForeignRow
Definition: fdwapi.h:248
Form_pg_class rd_rel
Definition: rel.h:111
bool traversed
Definition: tableam.h:152
TM_Result
Definition: tableam.h:79
@ TM_Ok
Definition: tableam.h:84
@ TM_Deleted
Definition: tableam.h:99
@ TM_WouldBlock
Definition: tableam.h:109
@ TM_Updated
Definition: tableam.h:96
@ TM_SelfModified
Definition: tableam.h:90
@ TM_Invisible
Definition: tableam.h:87
static TM_Result table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, uint8 flags, TM_FailureData *tmfd)
Definition: tableam.h:1585
#define TUPLE_LOCK_FLAG_FIND_LAST_VERSION
Definition: tableam.h:267
#define TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS
Definition: tableam.h:265
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define TupIsNull(slot)
Definition: tuptable.h:306
#define IsolationUsesXactSnapshot()
Definition: xact.h:51

References Assert, castNode, CHECK_FOR_INTERRUPTS, ExecAuxRowMark::ctidAttNo, ExecRowMark::curCtid, DatumGetObjectId(), DatumGetPointer(), elog, ereport, ExecRowMark::ermActive, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, errmsg(), ERROR, EState::es_output_cid, EState::es_snapshot, EvalPlanQualBegin(), EvalPlanQualEnd(), EvalPlanQualNext(), EvalPlanQualSetSlot, EvalPlanQualSlot(), ExecClearTuple(), ExecGetJunkAttribute(), ExecProcNode(), GetFdwRoutineForRelation(), IsolationUsesXactSnapshot, ItemPointerSetInvalid(), lfirst, lnext(), LockTupleExclusive, LockTupleKeyShare, LockTupleNoKeyExclusive, LockTupleShare, LockRowsState::lr_arowMarks, LockRowsState::lr_epqstate, ExecRowMark::markType, OidIsValid, outerPlan, outerPlanState, ExecRowMark::prti, LockRowsState::ps, RelationData::rd_rel, FdwRoutine::RefetchForeignRow, ExecRowMark::relation, RelationGetRelationName, ExecRowMark::relid, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_SHARE, ExecAuxRowMark::rowmark, ExecRowMark::rti, PlanState::state, table_tuple_lock(), test(), TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TM_WouldBlock, ExecAuxRowMark::toidAttNo, TM_FailureData::traversed, TupIsNull, TUPLE_LOCK_FLAG_FIND_LAST_VERSION, TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS, and ExecRowMark::waitPolicy.

Referenced by ExecInitLockRows().

◆ ExecReScanLockRows()

void ExecReScanLockRows ( LockRowsState node)

Definition at line 394 of file nodeLockRows.c.

395{
397
398 /*
399 * if chgParam of subnode is not null then plan will be re-scanned by
400 * first ExecProcNode.
401 */
402 if (outerPlan->chgParam == NULL)
404}
void ExecReScan(PlanState *node)
Definition: execAmi.c:76

References ExecReScan(), outerPlan, and outerPlanState.

Referenced by ExecReScan().