PostgreSQL Source Code  git master
nodeLockRows.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeLockRows.c
4  * Routines to handle FOR UPDATE/FOR SHARE row locking
5  *
6  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/nodeLockRows.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  * ExecLockRows - fetch locked rows
18  * ExecInitLockRows - initialize node and subnodes..
19  * ExecEndLockRows - shutdown node and subnodes
20  */
21 
22 #include "postgres.h"
23 
24 #include "access/htup_details.h"
25 #include "access/xact.h"
26 #include "executor/executor.h"
27 #include "executor/nodeLockRows.h"
28 #include "foreign/fdwapi.h"
29 #include "miscadmin.h"
30 #include "storage/bufmgr.h"
31 #include "utils/rel.h"
32 #include "utils/tqual.h"
33 
34 
35 /* ----------------------------------------------------------------
36  * ExecLockRows
37  * ----------------------------------------------------------------
38  */
39 static TupleTableSlot * /* return: a tuple or NULL */
41 {
42  LockRowsState *node = castNode(LockRowsState, pstate);
43  TupleTableSlot *slot;
44  EState *estate;
46  bool epq_needed;
47  ListCell *lc;
48 
50 
51  /*
52  * get information from the node
53  */
54  estate = node->ps.state;
55  outerPlan = outerPlanState(node);
56 
57  /*
58  * Get next tuple from subplan, if any.
59  */
60 lnext:
61  slot = ExecProcNode(outerPlan);
62 
63  if (TupIsNull(slot))
64  return NULL;
65 
66  /* We don't need EvalPlanQual unless we get updated tuple version(s) */
67  epq_needed = false;
68 
69  /*
70  * Attempt to lock the source tuple(s). (Note we only have locking
71  * rowmarks in lr_arowMarks.)
72  */
73  foreach(lc, node->lr_arowMarks)
74  {
75  ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
76  ExecRowMark *erm = aerm->rowmark;
77  HeapTuple *testTuple;
78  Datum datum;
79  bool isNull;
80  HeapTupleData tuple;
81  Buffer buffer;
83  LockTupleMode lockmode;
85  HeapTuple copyTuple;
86 
87  /* clear any leftover test tuple for this rel */
88  testTuple = &(node->lr_curtuples[erm->rti - 1]);
89  if (*testTuple != NULL)
90  heap_freetuple(*testTuple);
91  *testTuple = NULL;
92 
93  /* if child rel, must check whether it produced this row */
94  if (erm->rti != erm->prti)
95  {
96  Oid tableoid;
97 
98  datum = ExecGetJunkAttribute(slot,
99  aerm->toidAttNo,
100  &isNull);
101  /* shouldn't ever get a null result... */
102  if (isNull)
103  elog(ERROR, "tableoid is NULL");
104  tableoid = DatumGetObjectId(datum);
105 
106  Assert(OidIsValid(erm->relid));
107  if (tableoid != erm->relid)
108  {
109  /* this child is inactive right now */
110  erm->ermActive = false;
112  continue;
113  }
114  }
115  erm->ermActive = true;
116 
117  /* fetch the tuple's ctid */
118  datum = ExecGetJunkAttribute(slot,
119  aerm->ctidAttNo,
120  &isNull);
121  /* shouldn't ever get a null result... */
122  if (isNull)
123  elog(ERROR, "ctid is NULL");
124 
125  /* requests for foreign tables must be passed to their FDW */
126  if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
127  {
128  FdwRoutine *fdwroutine;
129  bool updated = false;
130 
131  fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
132  /* this should have been checked already, but let's be safe */
133  if (fdwroutine->RefetchForeignRow == NULL)
134  ereport(ERROR,
135  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
136  errmsg("cannot lock rows in foreign table \"%s\"",
138  copyTuple = fdwroutine->RefetchForeignRow(estate,
139  erm,
140  datum,
141  &updated);
142  if (copyTuple == NULL)
143  {
144  /* couldn't get the lock, so skip this row */
145  goto lnext;
146  }
147 
148  /* save locked tuple for possible EvalPlanQual testing below */
149  *testTuple = copyTuple;
150 
151  /*
152  * if FDW says tuple was updated before getting locked, we need to
153  * perform EPQ testing to see if quals are still satisfied
154  */
155  if (updated)
156  epq_needed = true;
157 
158  continue;
159  }
160 
161  /* okay, try to lock the tuple */
162  tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
163  switch (erm->markType)
164  {
165  case ROW_MARK_EXCLUSIVE:
166  lockmode = LockTupleExclusive;
167  break;
169  lockmode = LockTupleNoKeyExclusive;
170  break;
171  case ROW_MARK_SHARE:
172  lockmode = LockTupleShare;
173  break;
174  case ROW_MARK_KEYSHARE:
175  lockmode = LockTupleKeyShare;
176  break;
177  default:
178  elog(ERROR, "unsupported rowmark type");
179  lockmode = LockTupleNoKeyExclusive; /* keep compiler quiet */
180  break;
181  }
182 
183  test = heap_lock_tuple(erm->relation, &tuple,
184  estate->es_output_cid,
185  lockmode, erm->waitPolicy, true,
186  &buffer, &hufd);
187  ReleaseBuffer(buffer);
188  switch (test)
189  {
190  case HeapTupleWouldBlock:
191  /* couldn't lock tuple in SKIP LOCKED mode */
192  goto lnext;
193 
195 
196  /*
197  * The target tuple was already updated or deleted by the
198  * current command, or by a later command in the current
199  * transaction. We *must* ignore the tuple in the former
200  * case, so as to avoid the "Halloween problem" of repeated
201  * update attempts. In the latter case it might be sensible
202  * to fetch the updated tuple instead, but doing so would
203  * require changing heap_update and heap_delete to not
204  * complain about updating "invisible" tuples, which seems
205  * pretty scary (heap_lock_tuple will not complain, but few
206  * callers expect HeapTupleInvisible, and we're not one of
207  * them). So for now, treat the tuple as deleted and do not
208  * process.
209  */
210  goto lnext;
211 
213  /* got the lock successfully */
214  break;
215 
216  case HeapTupleUpdated:
218  ereport(ERROR,
219  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
220  errmsg("could not serialize access due to concurrent update")));
222  ereport(ERROR,
223  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
224  errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
225 
226  if (ItemPointerEquals(&hufd.ctid, &tuple.t_self))
227  {
228  /* Tuple was deleted, so don't return it */
229  goto lnext;
230  }
231 
232  /* updated, so fetch and lock the updated version */
233  copyTuple = EvalPlanQualFetch(estate, erm->relation,
234  lockmode, erm->waitPolicy,
235  &hufd.ctid, hufd.xmax);
236 
237  if (copyTuple == NULL)
238  {
239  /*
240  * Tuple was deleted; or it's locked and we're under SKIP
241  * LOCKED policy, so don't return it
242  */
243  goto lnext;
244  }
245  /* remember the actually locked tuple's TID */
246  tuple.t_self = copyTuple->t_self;
247 
248  /* Save locked tuple for EvalPlanQual testing below */
249  *testTuple = copyTuple;
250 
251  /* Remember we need to do EPQ testing */
252  epq_needed = true;
253 
254  /* Continue loop until we have all target tuples */
255  break;
256 
257  case HeapTupleInvisible:
258  elog(ERROR, "attempted to lock invisible tuple");
259  break;
260 
261  default:
262  elog(ERROR, "unrecognized heap_lock_tuple status: %u",
263  test);
264  }
265 
266  /* Remember locked tuple's TID for EPQ testing and WHERE CURRENT OF */
267  erm->curCtid = tuple.t_self;
268  }
269 
270  /*
271  * If we need to do EvalPlanQual testing, do so.
272  */
273  if (epq_needed)
274  {
275  /* Initialize EPQ machinery */
276  EvalPlanQualBegin(&node->lr_epqstate, estate);
277 
278  /*
279  * Transfer any already-fetched tuples into the EPQ state, and fetch a
280  * copy of any rows that were successfully locked without any update
281  * having occurred. (We do this in a separate pass so as to avoid
282  * overhead in the common case where there are no concurrent updates.)
283  * Make sure any inactive child rels have NULL test tuples in EPQ.
284  */
285  foreach(lc, node->lr_arowMarks)
286  {
287  ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
288  ExecRowMark *erm = aerm->rowmark;
289  HeapTupleData tuple;
290  Buffer buffer;
291 
292  /* skip non-active child tables, but clear their test tuples */
293  if (!erm->ermActive)
294  {
295  Assert(erm->rti != erm->prti); /* check it's child table */
296  EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti, NULL);
297  continue;
298  }
299 
300  /* was tuple updated and fetched above? */
301  if (node->lr_curtuples[erm->rti - 1] != NULL)
302  {
303  /* yes, so set it as the EPQ test tuple for this rel */
305  erm->rti,
306  node->lr_curtuples[erm->rti - 1]);
307  /* freeing this tuple is now the responsibility of EPQ */
308  node->lr_curtuples[erm->rti - 1] = NULL;
309  continue;
310  }
311 
312  /* foreign tables should have been fetched above */
313  Assert(erm->relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
315 
316  /* okay, fetch the tuple */
317  tuple.t_self = erm->curCtid;
318  if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
319  false, NULL))
320  elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
321 
322  /* successful, copy and store tuple */
323  EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti,
324  heap_copytuple(&tuple));
325  ReleaseBuffer(buffer);
326  }
327 
328  /*
329  * Now fetch any non-locked source rows --- the EPQ logic knows how to
330  * do that.
331  */
332  EvalPlanQualSetSlot(&node->lr_epqstate, slot);
334 
335  /*
336  * And finally we can re-evaluate the tuple.
337  */
338  slot = EvalPlanQualNext(&node->lr_epqstate);
339  if (TupIsNull(slot))
340  {
341  /* Updated tuple fails qual, so ignore it and go on */
342  goto lnext;
343  }
344  }
345 
346  /* Got all locks, so return the current tuple */
347  return slot;
348 }
349 
350 /* ----------------------------------------------------------------
351  * ExecInitLockRows
352  *
353  * This initializes the LockRows node state structures and
354  * the node's subplan.
355  * ----------------------------------------------------------------
356  */
358 ExecInitLockRows(LockRows *node, EState *estate, int eflags)
359 {
360  LockRowsState *lrstate;
361  Plan *outerPlan = outerPlan(node);
362  List *epq_arowmarks;
363  ListCell *lc;
364 
365  /* check for unsupported flags */
366  Assert(!(eflags & EXEC_FLAG_MARK));
367 
368  /*
369  * create state structure
370  */
371  lrstate = makeNode(LockRowsState);
372  lrstate->ps.plan = (Plan *) node;
373  lrstate->ps.state = estate;
374  lrstate->ps.ExecProcNode = ExecLockRows;
375 
376  /*
377  * Miscellaneous initialization
378  *
379  * LockRows nodes never call ExecQual or ExecProject, therefore no
380  * ExprContext is needed.
381  */
382 
383  /*
384  * Tuple table initialization (XXX not actually used, but upper nodes
385  * access it to get this node's result tupledesc...)
386  */
387  ExecInitResultTupleSlotTL(estate, &lrstate->ps);
388 
389  /*
390  * then initialize outer plan
391  */
392  outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
393 
394  /*
395  * LockRows nodes do no projections, so initialize projection info for
396  * this node appropriately
397  */
398  lrstate->ps.ps_ProjInfo = NULL;
399 
400  /*
401  * Create workspace in which we can remember per-RTE locked tuples
402  */
403  lrstate->lr_ntables = list_length(estate->es_range_table);
404  lrstate->lr_curtuples = (HeapTuple *)
405  palloc0(lrstate->lr_ntables * sizeof(HeapTuple));
406 
407  /*
408  * Locate the ExecRowMark(s) that this node is responsible for, and
409  * construct ExecAuxRowMarks for them. (InitPlan should already have
410  * built the global list of ExecRowMarks.)
411  */
412  lrstate->lr_arowMarks = NIL;
413  epq_arowmarks = NIL;
414  foreach(lc, node->rowMarks)
415  {
417  ExecRowMark *erm;
418  ExecAuxRowMark *aerm;
419 
420  /* ignore "parent" rowmarks; they are irrelevant at runtime */
421  if (rc->isParent)
422  continue;
423 
424  /* safety check on size of lr_curtuples array */
425  Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
426 
427  /* find ExecRowMark and build ExecAuxRowMark */
428  erm = ExecFindRowMark(estate, rc->rti, false);
429  aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
430 
431  /*
432  * Only locking rowmarks go into our own list. Non-locking marks are
433  * passed off to the EvalPlanQual machinery. This is because we don't
434  * want to bother fetching non-locked rows unless we actually have to
435  * do an EPQ recheck.
436  */
438  lrstate->lr_arowMarks = lappend(lrstate->lr_arowMarks, aerm);
439  else
440  epq_arowmarks = lappend(epq_arowmarks, aerm);
441  }
442 
443  /* Now we have the info needed to set up EPQ state */
444  EvalPlanQualInit(&lrstate->lr_epqstate, estate,
445  outerPlan, epq_arowmarks, node->epqParam);
446 
447  return lrstate;
448 }
449 
450 /* ----------------------------------------------------------------
451  * ExecEndLockRows
452  *
453  * This shuts down the subplan and frees resources allocated
454  * to this node.
455  * ----------------------------------------------------------------
456  */
457 void
459 {
462 }
463 
464 
465 void
467 {
468  /*
469  * if chgParam of subnode is not null then plan will be re-scanned by
470  * first ExecProcNode.
471  */
472  if (node->ps.lefttree->chgParam == NULL)
473  ExecReScan(node->ps.lefttree);
474 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
#define NIL
Definition: pg_list.h:69
HeapTuple * lr_curtuples
Definition: execnodes.h:2181
CommandId es_output_cid
Definition: execnodes.h:487
static void test(void)
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:948
EPQState lr_epqstate
Definition: execnodes.h:2180
HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, HeapUpdateFailureData *hufd)
Definition: heapam.c:4688
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:538
void EvalPlanQualSetTuple(EPQState *epqstate, Index rti, HeapTuple tuple)
Definition: execMain.c:2865
Relation relation
Definition: execnodes.h:596
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1903
LockRowsState * ExecInitLockRows(LockRows *node, EState *estate, int eflags)
Definition: nodeLockRows.c:358
#define DatumGetObjectId(X)
Definition: postgres.h:485
HeapTuple EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, LockWaitPolicy wait_policy, ItemPointer tid, TransactionId priorXmax)
Definition: execMain.c:2588
void ExecReScanLockRows(LockRowsState *node)
Definition: nodeLockRows.c:466
void EvalPlanQualFetchRowMarks(EPQState *epqstate)
Definition: execMain.c:2900
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
void ExecEndLockRows(LockRowsState *node)
Definition: nodeLockRows.c:458
#define IsolationUsesXactSnapshot()
Definition: xact.h:50
static TupleTableSlot * ExecLockRows(PlanState *pstate)
Definition: nodeLockRows.c:40
int errcode(int sqlerrcode)
Definition: elog.c:575
bool ermActive
Definition: execnodes.h:604
int epqParam
Definition: plannodes.h:936
LockWaitPolicy waitPolicy
Definition: execnodes.h:603
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
EState * state
Definition: execnodes.h:914
List * es_range_table
Definition: execnodes.h:480
Form_pg_class rd_rel
Definition: rel.h:84
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:994
void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate)
Definition: execMain.c:3060
TupleTableSlot * EvalPlanQualNext(EPQState *epqstate)
Definition: execMain.c:3044
struct PlanState * lefttree
Definition: execnodes.h:931
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3253
ItemPointerData * ItemPointer
Definition: itemptr.h:49
ExecRowMark * rowmark
Definition: execnodes.h:623
ItemPointerData curCtid
Definition: execnodes.h:605
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define outerPlanState(node)
Definition: execnodes.h:966
PlanState ps
Definition: execnodes.h:2178
Index rti
Definition: execnodes.h:598
Index prti
Definition: execnodes.h:599
HTSU_Result
Definition: snapshot.h:121
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define TupIsNull(slot)
Definition: tuptable.h:146
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
Bitmapset * chgParam
Definition: execnodes.h:941
#define outerPlan(node)
Definition: plannodes.h:176
List * lappend(List *list, void *datum)
Definition: list.c:128
TransactionId xmax
Definition: heapam.h:71
void * palloc0(Size size)
Definition: mcxt.c:955
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:918
uintptr_t Datum
Definition: postgres.h:367
#define SnapshotAny
Definition: tqual.h:28
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:233
#define ItemPointerIndicatesMovedPartitions(pointer)
Definition: itemptr.h:184
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:890
void EvalPlanQualInit(EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2830
Plan * plan
Definition: execnodes.h:912
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
#define EXEC_FLAG_MARK
Definition: executor.h:61
List * rowMarks
Definition: plannodes.h:935
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
RowMarkType markType
Definition: execnodes.h:601
static int list_length(const List *l)
Definition: pg_list.h:89
AttrNumber toidAttNo
Definition: execnodes.h:625
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
List * targetlist
Definition: plannodes.h:146
#define DatumGetPointer(X)
Definition: postgres.h:534
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
int errmsg(const char *fmt,...)
Definition: elog.c:797
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:248
List * lr_arowMarks
Definition: execnodes.h:2179
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
bool isParent
Definition: plannodes.h:1045
ItemPointerData ctid
Definition: heapam.h:70
#define elog
Definition: elog.h:219
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
Definition: pg_list.h:45
int Buffer
Definition: buf.h:23
AttrNumber ctidAttNo
Definition: execnodes.h:624
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2430
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:208
RefetchForeignRow_function RefetchForeignRow
Definition: fdwapi.h:224
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2406