PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeLockRows.h File Reference
#include "nodes/execnodes.h"
Include dependency graph for nodeLockRows.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

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

Function Documentation

void ExecEndLockRows ( LockRowsState node)

Definition at line 446 of file nodeLockRows.c.

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

Referenced by ExecEndNode().

447 {
450 }
EPQState lr_epqstate
Definition: execnodes.h:1969
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:654
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3162
#define outerPlanState(node)
Definition: execnodes.h:855
LockRowsState* ExecInitLockRows ( LockRows node,
EState estate,
int  eflags 
)

Definition at line 348 of file nodeLockRows.c.

References Assert, LockRows::epqParam, EState::es_range_table, EvalPlanQualInit(), EXEC_FLAG_MARK, ExecAssignResultTypeFromTL(), ExecBuildAuxRowMark(), ExecFindRowMark(), ExecInitNode(), ExecInitResultTupleSlot(), PlanRowMark::isParent, lappend(), lfirst_node, list_length(), LockRowsState::lr_arowMarks, LockRowsState::lr_curtuples, LockRowsState::lr_epqstate, LockRowsState::lr_ntables, makeNode, ExecRowMark::markType, NIL, NULL, outerPlan, outerPlanState, palloc0(), PlanState::plan, LockRowsState::ps, PlanState::ps_ProjInfo, RowMarkRequiresRowShareLock, LockRows::rowMarks, PlanRowMark::rti, PlanState::state, and Plan::targetlist.

Referenced by ExecInitNode().

349 {
350  LockRowsState *lrstate;
351  Plan *outerPlan = outerPlan(node);
352  List *epq_arowmarks;
353  ListCell *lc;
354 
355  /* check for unsupported flags */
356  Assert(!(eflags & EXEC_FLAG_MARK));
357 
358  /*
359  * create state structure
360  */
361  lrstate = makeNode(LockRowsState);
362  lrstate->ps.plan = (Plan *) node;
363  lrstate->ps.state = estate;
364 
365  /*
366  * Miscellaneous initialization
367  *
368  * LockRows nodes never call ExecQual or ExecProject.
369  */
370 
371  /*
372  * Tuple table initialization (XXX not actually used...)
373  */
374  ExecInitResultTupleSlot(estate, &lrstate->ps);
375 
376  /*
377  * then initialize outer plan
378  */
379  outerPlanState(lrstate) = ExecInitNode(outerPlan, estate, eflags);
380 
381  /*
382  * LockRows nodes do no projections, so initialize projection info for
383  * this node appropriately
384  */
385  ExecAssignResultTypeFromTL(&lrstate->ps);
386  lrstate->ps.ps_ProjInfo = NULL;
387 
388  /*
389  * Create workspace in which we can remember per-RTE locked tuples
390  */
391  lrstate->lr_ntables = list_length(estate->es_range_table);
392  lrstate->lr_curtuples = (HeapTuple *)
393  palloc0(lrstate->lr_ntables * sizeof(HeapTuple));
394 
395  /*
396  * Locate the ExecRowMark(s) that this node is responsible for, and
397  * construct ExecAuxRowMarks for them. (InitPlan should already have
398  * built the global list of ExecRowMarks.)
399  */
400  lrstate->lr_arowMarks = NIL;
401  epq_arowmarks = NIL;
402  foreach(lc, node->rowMarks)
403  {
405  ExecRowMark *erm;
406  ExecAuxRowMark *aerm;
407 
408  /* ignore "parent" rowmarks; they are irrelevant at runtime */
409  if (rc->isParent)
410  continue;
411 
412  /* safety check on size of lr_curtuples array */
413  Assert(rc->rti > 0 && rc->rti <= lrstate->lr_ntables);
414 
415  /* find ExecRowMark and build ExecAuxRowMark */
416  erm = ExecFindRowMark(estate, rc->rti, false);
417  aerm = ExecBuildAuxRowMark(erm, outerPlan->targetlist);
418 
419  /*
420  * Only locking rowmarks go into our own list. Non-locking marks are
421  * passed off to the EvalPlanQual machinery. This is because we don't
422  * want to bother fetching non-locked rows unless we actually have to
423  * do an EPQ recheck.
424  */
426  lrstate->lr_arowMarks = lappend(lrstate->lr_arowMarks, aerm);
427  else
428  epq_arowmarks = lappend(epq_arowmarks, aerm);
429  }
430 
431  /* Now we have the info needed to set up EPQ state */
432  EvalPlanQualInit(&lrstate->lr_epqstate, estate,
433  outerPlan, epq_arowmarks, node->epqParam);
434 
435  return lrstate;
436 }
#define NIL
Definition: pg_list.h:69
HeapTuple * lr_curtuples
Definition: execnodes.h:1970
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:844
EPQState lr_epqstate
Definition: execnodes.h:1969
int epqParam
Definition: plannodes.h:904
EState * state
Definition: execnodes.h:815
List * es_range_table
Definition: execnodes.h:411
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:962
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define outerPlanState(node)
Definition: execnodes.h:855
PlanState ps
Definition: execnodes.h:1967
#define outerPlan(node)
Definition: plannodes.h:174
List * lappend(List *list, void *datum)
Definition: list.c:128
void * palloc0(Size size)
Definition: mcxt.c:878
void EvalPlanQualInit(EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
Definition: execMain.c:2751
Plan * plan
Definition: execnodes.h:813
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define EXEC_FLAG_MARK
Definition: executor.h:61
List * rowMarks
Definition: plannodes.h:903
RowMarkType markType
Definition: execnodes.h:516
static int list_length(const List *l)
Definition: pg_list.h:89
List * targetlist
Definition: plannodes.h:144
List * lr_arowMarks
Definition: execnodes.h:1968
bool isParent
Definition: plannodes.h:1013
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:140
Definition: pg_list.h:45
ExecAuxRowMark * ExecBuildAuxRowMark(ExecRowMark *erm, List *targetlist)
Definition: execMain.c:2364
ExecRowMark * ExecFindRowMark(EState *estate, Index rti, bool missing_ok)
Definition: execMain.c:2340
TupleTableSlot* ExecLockRows ( LockRowsState node)

Definition at line 39 of file nodeLockRows.c.

References Assert, buffer, HeapUpdateFailureData::ctid, ExecAuxRowMark::ctidAttNo, ExecRowMark::curCtid, DatumGetObjectId, DatumGetPointer, elog, ereport, ExecRowMark::ermActive, errcode(), errmsg(), ERROR, EState::es_output_cid, EvalPlanQualBegin(), EvalPlanQualFetch(), EvalPlanQualFetchRowMarks(), EvalPlanQualNext(), EvalPlanQualSetSlot, EvalPlanQualSetTuple(), ExecGetJunkAttribute(), ExecProcNode(), GetFdwRoutineForRelation(), heap_copytuple(), heap_fetch(), heap_freetuple(), heap_lock_tuple(), HeapTupleInvisible, HeapTupleMayBeUpdated, HeapTupleSelfUpdated, HeapTupleUpdated, HeapTupleWouldBlock, IsolationUsesXactSnapshot, ItemPointerEquals(), ItemPointerIsValid, ItemPointerSetInvalid, lfirst, lnext, LockTupleExclusive, LockTupleKeyShare, LockTupleNoKeyExclusive, LockTupleShare, LockRowsState::lr_arowMarks, LockRowsState::lr_curtuples, LockRowsState::lr_epqstate, ExecRowMark::markType, NULL, OidIsValid, outerPlan, outerPlanState, ExecRowMark::prti, LockRowsState::ps, RelationData::rd_rel, FdwRoutine::RefetchForeignRow, ExecRowMark::relation, RelationGetRelationName, ReleaseBuffer(), ExecRowMark::relid, RELKIND_FOREIGN_TABLE, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_SHARE, ExecAuxRowMark::rowmark, ExecRowMark::rti, SnapshotAny, PlanState::state, HeapTupleData::t_self, test(), ExecAuxRowMark::toidAttNo, TupIsNull, ExecRowMark::waitPolicy, and HeapUpdateFailureData::xmax.

Referenced by ExecProcNode().

40 {
41  TupleTableSlot *slot;
42  EState *estate;
44  bool epq_needed;
45  ListCell *lc;
46 
47  /*
48  * get information from the node
49  */
50  estate = node->ps.state;
51  outerPlan = outerPlanState(node);
52 
53  /*
54  * Get next tuple from subplan, if any.
55  */
56 lnext:
57  slot = ExecProcNode(outerPlan);
58 
59  if (TupIsNull(slot))
60  return NULL;
61 
62  /* We don't need EvalPlanQual unless we get updated tuple version(s) */
63  epq_needed = false;
64 
65  /*
66  * Attempt to lock the source tuple(s). (Note we only have locking
67  * rowmarks in lr_arowMarks.)
68  */
69  foreach(lc, node->lr_arowMarks)
70  {
71  ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
72  ExecRowMark *erm = aerm->rowmark;
73  HeapTuple *testTuple;
74  Datum datum;
75  bool isNull;
76  HeapTupleData tuple;
77  Buffer buffer;
79  LockTupleMode lockmode;
81  HeapTuple copyTuple;
82 
83  /* clear any leftover test tuple for this rel */
84  testTuple = &(node->lr_curtuples[erm->rti - 1]);
85  if (*testTuple != NULL)
86  heap_freetuple(*testTuple);
87  *testTuple = NULL;
88 
89  /* if child rel, must check whether it produced this row */
90  if (erm->rti != erm->prti)
91  {
92  Oid tableoid;
93 
94  datum = ExecGetJunkAttribute(slot,
95  aerm->toidAttNo,
96  &isNull);
97  /* shouldn't ever get a null result... */
98  if (isNull)
99  elog(ERROR, "tableoid is NULL");
100  tableoid = DatumGetObjectId(datum);
101 
102  Assert(OidIsValid(erm->relid));
103  if (tableoid != erm->relid)
104  {
105  /* this child is inactive right now */
106  erm->ermActive = false;
108  continue;
109  }
110  }
111  erm->ermActive = true;
112 
113  /* fetch the tuple's ctid */
114  datum = ExecGetJunkAttribute(slot,
115  aerm->ctidAttNo,
116  &isNull);
117  /* shouldn't ever get a null result... */
118  if (isNull)
119  elog(ERROR, "ctid is NULL");
120 
121  /* requests for foreign tables must be passed to their FDW */
122  if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
123  {
124  FdwRoutine *fdwroutine;
125  bool updated = false;
126 
127  fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
128  /* this should have been checked already, but let's be safe */
129  if (fdwroutine->RefetchForeignRow == NULL)
130  ereport(ERROR,
131  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
132  errmsg("cannot lock rows in foreign table \"%s\"",
134  copyTuple = fdwroutine->RefetchForeignRow(estate,
135  erm,
136  datum,
137  &updated);
138  if (copyTuple == NULL)
139  {
140  /* couldn't get the lock, so skip this row */
141  goto lnext;
142  }
143 
144  /* save locked tuple for possible EvalPlanQual testing below */
145  *testTuple = copyTuple;
146 
147  /*
148  * if FDW says tuple was updated before getting locked, we need to
149  * perform EPQ testing to see if quals are still satisfied
150  */
151  if (updated)
152  epq_needed = true;
153 
154  continue;
155  }
156 
157  /* okay, try to lock the tuple */
158  tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
159  switch (erm->markType)
160  {
161  case ROW_MARK_EXCLUSIVE:
162  lockmode = LockTupleExclusive;
163  break;
165  lockmode = LockTupleNoKeyExclusive;
166  break;
167  case ROW_MARK_SHARE:
168  lockmode = LockTupleShare;
169  break;
170  case ROW_MARK_KEYSHARE:
171  lockmode = LockTupleKeyShare;
172  break;
173  default:
174  elog(ERROR, "unsupported rowmark type");
175  lockmode = LockTupleNoKeyExclusive; /* keep compiler quiet */
176  break;
177  }
178 
179  test = heap_lock_tuple(erm->relation, &tuple,
180  estate->es_output_cid,
181  lockmode, erm->waitPolicy, true,
182  &buffer, &hufd);
183  ReleaseBuffer(buffer);
184  switch (test)
185  {
186  case HeapTupleWouldBlock:
187  /* couldn't lock tuple in SKIP LOCKED mode */
188  goto lnext;
189 
191 
192  /*
193  * The target tuple was already updated or deleted by the
194  * current command, or by a later command in the current
195  * transaction. We *must* ignore the tuple in the former
196  * case, so as to avoid the "Halloween problem" of repeated
197  * update attempts. In the latter case it might be sensible
198  * to fetch the updated tuple instead, but doing so would
199  * require changing heap_update and heap_delete to not
200  * complain about updating "invisible" tuples, which seems
201  * pretty scary (heap_lock_tuple will not complain, but few
202  * callers expect HeapTupleInvisible, and we're not one of
203  * them). So for now, treat the tuple as deleted and do not
204  * process.
205  */
206  goto lnext;
207 
209  /* got the lock successfully */
210  break;
211 
212  case HeapTupleUpdated:
214  ereport(ERROR,
215  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
216  errmsg("could not serialize access due to concurrent update")));
217  if (ItemPointerEquals(&hufd.ctid, &tuple.t_self))
218  {
219  /* Tuple was deleted, so don't return it */
220  goto lnext;
221  }
222 
223  /* updated, so fetch and lock the updated version */
224  copyTuple = EvalPlanQualFetch(estate, erm->relation,
225  lockmode, erm->waitPolicy,
226  &hufd.ctid, hufd.xmax);
227 
228  if (copyTuple == NULL)
229  {
230  /*
231  * Tuple was deleted; or it's locked and we're under SKIP
232  * LOCKED policy, so don't return it
233  */
234  goto lnext;
235  }
236  /* remember the actually locked tuple's TID */
237  tuple.t_self = copyTuple->t_self;
238 
239  /* Save locked tuple for EvalPlanQual testing below */
240  *testTuple = copyTuple;
241 
242  /* Remember we need to do EPQ testing */
243  epq_needed = true;
244 
245  /* Continue loop until we have all target tuples */
246  break;
247 
248  case HeapTupleInvisible:
249  elog(ERROR, "attempted to lock invisible tuple");
250 
251  default:
252  elog(ERROR, "unrecognized heap_lock_tuple status: %u",
253  test);
254  }
255 
256  /* Remember locked tuple's TID for EPQ testing and WHERE CURRENT OF */
257  erm->curCtid = tuple.t_self;
258  }
259 
260  /*
261  * If we need to do EvalPlanQual testing, do so.
262  */
263  if (epq_needed)
264  {
265  /* Initialize EPQ machinery */
266  EvalPlanQualBegin(&node->lr_epqstate, estate);
267 
268  /*
269  * Transfer any already-fetched tuples into the EPQ state, and fetch a
270  * copy of any rows that were successfully locked without any update
271  * having occurred. (We do this in a separate pass so as to avoid
272  * overhead in the common case where there are no concurrent updates.)
273  * Make sure any inactive child rels have NULL test tuples in EPQ.
274  */
275  foreach(lc, node->lr_arowMarks)
276  {
277  ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(lc);
278  ExecRowMark *erm = aerm->rowmark;
279  HeapTupleData tuple;
280  Buffer buffer;
281 
282  /* skip non-active child tables, but clear their test tuples */
283  if (!erm->ermActive)
284  {
285  Assert(erm->rti != erm->prti); /* check it's child table */
286  EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti, NULL);
287  continue;
288  }
289 
290  /* was tuple updated and fetched above? */
291  if (node->lr_curtuples[erm->rti - 1] != NULL)
292  {
293  /* yes, so set it as the EPQ test tuple for this rel */
295  erm->rti,
296  node->lr_curtuples[erm->rti - 1]);
297  /* freeing this tuple is now the responsibility of EPQ */
298  node->lr_curtuples[erm->rti - 1] = NULL;
299  continue;
300  }
301 
302  /* foreign tables should have been fetched above */
303  Assert(erm->relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE);
305 
306  /* okay, fetch the tuple */
307  tuple.t_self = erm->curCtid;
308  if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
309  false, NULL))
310  elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
311 
312  /* successful, copy and store tuple */
313  EvalPlanQualSetTuple(&node->lr_epqstate, erm->rti,
314  heap_copytuple(&tuple));
315  ReleaseBuffer(buffer);
316  }
317 
318  /*
319  * Now fetch any non-locked source rows --- the EPQ logic knows how to
320  * do that.
321  */
322  EvalPlanQualSetSlot(&node->lr_epqstate, slot);
324 
325  /*
326  * And finally we can re-evaluate the tuple.
327  */
328  slot = EvalPlanQualNext(&node->lr_epqstate);
329  if (TupIsNull(slot))
330  {
331  /* Updated tuple fails qual, so ignore it and go on */
332  goto lnext;
333  }
334  }
335 
336  /* Got all locks, so return the current tuple */
337  return slot;
338 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
HeapTuple * lr_curtuples
Definition: execnodes.h:1970
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:398
CommandId es_output_cid
Definition: execnodes.h:418
static void test(void)
EPQState lr_epqstate
Definition: execnodes.h:1969
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:4540
void EvalPlanQualSetTuple(EPQState *epqstate, Index rti, HeapTuple tuple)
Definition: execMain.c:2786
Relation relation
Definition: execnodes.h:511
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1862
#define DatumGetObjectId(X)
Definition: postgres.h:506
HeapTuple EvalPlanQualFetch(EState *estate, Relation relation, int lockmode, LockWaitPolicy wait_policy, ItemPointer tid, TransactionId priorXmax)
Definition: execMain.c:2522
void EvalPlanQualFetchRowMarks(EPQState *epqstate)
Definition: execMain.c:2821
#define IsolationUsesXactSnapshot()
Definition: xact.h:43
int errcode(int sqlerrcode)
Definition: elog.c:575
bool ermActive
Definition: execnodes.h:519
LockWaitPolicy waitPolicy
Definition: execnodes.h:518
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
EState * state
Definition: execnodes.h:815
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate)
Definition: execMain.c:2972
TupleTableSlot * EvalPlanQualNext(EPQState *epqstate)
Definition: execMain.c:2956
ItemPointerData * ItemPointer
Definition: itemptr.h:48
ExecRowMark * rowmark
Definition: execnodes.h:538
ItemPointerData curCtid
Definition: execnodes.h:520
LockTupleMode
Definition: heapam.h:38
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define outerPlanState(node)
Definition: execnodes.h:855
PlanState ps
Definition: execnodes.h:1967
Index rti
Definition: execnodes.h:513
Index prti
Definition: execnodes.h:514
HTSU_Result
Definition: snapshot.h:119
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define TupIsNull(slot)
Definition: tuptable.h:138
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
#define outerPlan(node)
Definition: plannodes.h:174
TransactionId xmax
Definition: heapam.h:71
uintptr_t Datum
Definition: postgres.h:372
#define SnapshotAny
Definition: tqual.h:28
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
RowMarkType markType
Definition: execnodes.h:516
AttrNumber toidAttNo
Definition: execnodes.h:540
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
#define DatumGetPointer(X)
Definition: postgres.h:555
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:149
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:1968
ItemPointerData ctid
Definition: heapam.h:70
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
AttrNumber ctidAttNo
Definition: execnodes.h:539
#define EvalPlanQualSetSlot(epqstate, slot)
Definition: executor.h:220
RefetchForeignRow_function RefetchForeignRow
Definition: fdwapi.h:209
void ExecReScanLockRows ( LockRowsState node)

Definition at line 454 of file nodeLockRows.c.

References PlanState::chgParam, ExecReScan(), PlanState::lefttree, NULL, and LockRowsState::ps.

Referenced by ExecReScan().

455 {
456  /*
457  * if chgParam of subnode is not null then plan will be re-scanned by
458  * first ExecProcNode.
459  */
460  if (node->ps.lefttree->chgParam == NULL)
461  ExecReScan(node->ps.lefttree);
462 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:75
struct PlanState * lefttree
Definition: execnodes.h:828
PlanState ps
Definition: execnodes.h:1967
Bitmapset * chgParam
Definition: execnodes.h:837
#define NULL
Definition: c.h:229