PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
execReplication.c File Reference
#include "postgres.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "access/xact.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for execReplication.c:

Go to the source code of this file.

Functions

static bool build_replindex_scan_key (ScanKey skey, Relation rel, Relation idxrel, TupleTableSlot *searchslot)
 
bool RelationFindReplTupleByIndex (Relation rel, Oid idxoid, LockTupleMode lockmode, TupleTableSlot *searchslot, TupleTableSlot *outslot)
 
static bool tuple_equals_slot (TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
 
bool RelationFindReplTupleSeq (Relation rel, LockTupleMode lockmode, TupleTableSlot *searchslot, TupleTableSlot *outslot)
 
void ExecSimpleRelationInsert (EState *estate, TupleTableSlot *slot)
 
void ExecSimpleRelationUpdate (EState *estate, EPQState *epqstate, TupleTableSlot *searchslot, TupleTableSlot *slot)
 
void ExecSimpleRelationDelete (EState *estate, EPQState *epqstate, TupleTableSlot *searchslot)
 
void CheckCmdReplicaIdentity (Relation rel, CmdType cmd)
 

Function Documentation

static bool build_replindex_scan_key ( ScanKey  skey,
Relation  rel,
Relation  idxrel,
TupleTableSlot searchslot 
)
static

Definition at line 46 of file execReplication.c.

References Anum_pg_index_indclass, Assert, BTEqualStrategyNumber, DatumGetPointer, elog, ERROR, get_opclass_family(), get_opclass_input_type(), get_opcode(), get_opfamily_member(), INDEXRELID, OidIsValid, RelationData::rd_index, RelationData::rd_indextuple, RelationGetNumberOfAttributes, RelationGetRelid, RelationGetReplicaIndex(), ScanKeyInit(), ScanKeyData::sk_flags, SK_ISNULL, SysCacheGetAttr(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, int2vector::values, and oidvector::values.

Referenced by RelationFindReplTupleByIndex().

48 {
49  int attoff;
50  bool isnull;
51  Datum indclassDatum;
52  oidvector *opclass;
53  int2vector *indkey = &idxrel->rd_index->indkey;
54  bool hasnulls = false;
55 
57 
58  indclassDatum = SysCacheGetAttr(INDEXRELID, idxrel->rd_indextuple,
59  Anum_pg_index_indclass, &isnull);
60  Assert(!isnull);
61  opclass = (oidvector *) DatumGetPointer(indclassDatum);
62 
63  /* Build scankey for every attribute in the index. */
64  for (attoff = 0; attoff < RelationGetNumberOfAttributes(idxrel); attoff++)
65  {
66  Oid operator;
67  Oid opfamily;
68  RegProcedure regop;
69  int pkattno = attoff + 1;
70  int mainattno = indkey->values[attoff];
71  Oid optype = get_opclass_input_type(opclass->values[attoff]);
72 
73  /*
74  * Load the operator info. We need this to get the equality operator
75  * function for the scan key.
76  */
77  opfamily = get_opclass_family(opclass->values[attoff]);
78 
79  operator = get_opfamily_member(opfamily, optype,
80  optype,
82 
83  if (!OidIsValid(operator))
84  elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
85  BTEqualStrategyNumber, optype, optype, opfamily);
86 
87  regop = get_opcode(operator);
88 
89  /* Initialize the scankey. */
90  ScanKeyInit(&skey[attoff],
91  pkattno,
93  regop,
94  searchslot->tts_values[mainattno - 1]);
95 
96  /* Check for null value. */
97  if (searchslot->tts_isnull[mainattno - 1])
98  {
99  hasnulls = true;
100  skey[attoff].sk_flags |= SK_ISNULL;
101  }
102  }
103 
104  return hasnulls;
105 }
Definition: c.h:474
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4588
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:419
regproc RegProcedure
Definition: c.h:392
#define Anum_pg_index_indclass
Definition: pg_index.h:89
Datum * tts_values
Definition: tuptable.h:125
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
struct HeapTupleData * rd_indextuple
Definition: rel.h:157
Form_pg_index rd_index
Definition: rel.h:155
#define ERROR
Definition: elog.h:43
bool * tts_isnull
Definition: tuptable.h:126
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:482
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define SK_ISNULL
Definition: skey.h:115
Definition: c.h:463
uintptr_t Datum
Definition: postgres.h:374
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1062
int sk_flags
Definition: skey.h:66
#define Assert(condition)
Definition: c.h:671
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:471
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1015
#define DatumGetPointer(X)
Definition: postgres.h:557
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define RelationGetRelid(relation)
Definition: rel.h:413
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1037
void CheckCmdReplicaIdentity ( Relation  rel,
CmdType  cmd 
)

Definition at line 522 of file execReplication.c.

References CMD_DELETE, CMD_UPDATE, ereport, errcode(), errhint(), errmsg(), ERROR, GetRelationPublicationActions(), OidIsValid, PublicationActions::pubdelete, PublicationActions::pubupdate, RelationData::rd_rel, RelationGetRelationName, RelationGetReplicaIndex(), and REPLICA_IDENTITY_FULL.

Referenced by CheckValidResultRel(), ExecSimpleRelationDelete(), ExecSimpleRelationInsert(), and ExecSimpleRelationUpdate().

523 {
524  PublicationActions *pubactions;
525 
526  /* We only need to do checks for UPDATE and DELETE. */
527  if (cmd != CMD_UPDATE && cmd != CMD_DELETE)
528  return;
529 
530  /* If relation has replica identity we are always good. */
531  if (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL ||
533  return;
534 
535  /*
536  * This is either UPDATE OR DELETE and there is no replica identity.
537  *
538  * Check if the table publishes UPDATES or DELETES.
539  */
540  pubactions = GetRelationPublicationActions(rel);
541  if (cmd == CMD_UPDATE && pubactions->pubupdate)
542  ereport(ERROR,
543  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
544  errmsg("cannot update table \"%s\" because it does not have replica identity and publishes updates",
546  errhint("To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.")));
547  else if (cmd == CMD_DELETE && pubactions->pubdelete)
548  ereport(ERROR,
549  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
550  errmsg("cannot delete from table \"%s\" because it does not have replica identity and publishes deletes",
552  errhint("To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE.")));
553 }
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4588
int errcode(int sqlerrcode)
Definition: elog.c:575
Form_pg_class rd_rel
Definition: rel.h:113
#define OidIsValid(objectId)
Definition: c.h:534
#define REPLICA_IDENTITY_FULL
Definition: pg_class.h:179
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define ereport(elevel, rest)
Definition: elog.h:122
struct PublicationActions * GetRelationPublicationActions(Relation relation)
Definition: relcache.c:5084
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ExecSimpleRelationDelete ( EState estate,
EPQState epqstate,
TupleTableSlot searchslot 
)

Definition at line 482 of file execReplication.c.

References Assert, CheckCmdReplicaIdentity(), CMD_DELETE, EState::es_result_relation_info, ExecARDeleteTriggers(), ExecBRDeleteTriggers(), list_free(), NIL, NULL, RelationData::rd_rel, RELKIND_RELATION, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, simple_heap_delete(), HeapTupleData::t_self, TriggerDesc::trig_update_before_row, and TupleTableSlot::tts_tuple.

Referenced by apply_handle_delete().

484 {
485  bool skip_tuple = false;
486  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
487  Relation rel = resultRelInfo->ri_RelationDesc;
488 
489  /* For now we support only tables. */
490  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
491 
493 
494  /* BEFORE ROW INSERT Triggers */
495  if (resultRelInfo->ri_TrigDesc &&
496  resultRelInfo->ri_TrigDesc->trig_update_before_row)
497  {
498  skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
499  &searchslot->tts_tuple->t_self,
500  NULL);
501  }
502 
503  if (!skip_tuple)
504  {
505  List *recheckIndexes = NIL;
506 
507  /* OK, delete the tuple */
508  simple_heap_delete(rel, &searchslot->tts_tuple->t_self);
509 
510  /* AFTER ROW DELETE Triggers */
511  ExecARDeleteTriggers(estate, resultRelInfo,
512  &searchslot->tts_tuple->t_self, NULL);
513 
514  list_free(recheckIndexes);
515  }
516 }
#define NIL
Definition: pg_list.h:69
Relation ri_RelationDesc
Definition: execnodes.h:335
Form_pg_class rd_rel
Definition: rel.h:113
ItemPointerData t_self
Definition: htup.h:65
bool trig_update_before_row
Definition: reltrigger.h:60
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:339
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
Definition: trigger.c:2448
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
Definition: trigger.c:2379
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:3385
void list_free(List *list)
Definition: list.c:1133
HeapTuple tts_tuple
Definition: tuptable.h:120
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:384
void ExecSimpleRelationInsert ( EState estate,
TupleTableSlot slot 
)

Definition at line 364 of file execReplication.c.

References Assert, CheckCmdReplicaIdentity(), CMD_INSERT, tupleDesc::constr, EState::es_result_relation_info, ExecARInsertTriggers(), ExecBRInsertTriggers(), ExecConstraints(), ExecInsertIndexTuples(), ExecMaterializeSlot(), list_free(), NIL, NULL, RelationData::rd_att, RelationData::rd_rel, RELKIND_RELATION, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, simple_heap_insert(), HeapTupleData::t_self, and TriggerDesc::trig_insert_before_row.

Referenced by apply_handle_insert().

365 {
366  bool skip_tuple = false;
367  HeapTuple tuple;
368  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
369  Relation rel = resultRelInfo->ri_RelationDesc;
370 
371  /* For now we support only tables. */
372  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
373 
375 
376  /* BEFORE ROW INSERT Triggers */
377  if (resultRelInfo->ri_TrigDesc &&
378  resultRelInfo->ri_TrigDesc->trig_insert_before_row)
379  {
380  slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
381 
382  if (slot == NULL) /* "do nothing" */
383  skip_tuple = true;
384  }
385 
386  if (!skip_tuple)
387  {
388  List *recheckIndexes = NIL;
389 
390  /* Check the constraints of the tuple */
391  if (rel->rd_att->constr)
392  ExecConstraints(resultRelInfo, slot, slot, estate);
393 
394  /* Store the slot into tuple that we can inspect. */
395  tuple = ExecMaterializeSlot(slot);
396 
397  /* OK, store the tuple and create index entries for it */
398  simple_heap_insert(rel, tuple);
399 
400  if (resultRelInfo->ri_NumIndices > 0)
401  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
402  estate, false, NULL,
403  NIL);
404 
405  /* AFTER ROW INSERT Triggers */
406  ExecARInsertTriggers(estate, resultRelInfo, tuple,
407  recheckIndexes);
408 
409  list_free(recheckIndexes);
410  }
411 }
int ri_NumIndices
Definition: execnodes.h:336
#define NIL
Definition: pg_list.h:69
Relation ri_RelationDesc
Definition: execnodes.h:335
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
Form_pg_class rd_rel
Definition: rel.h:113
ItemPointerData t_self
Definition: htup.h:65
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:339
bool trig_insert_before_row
Definition: reltrigger.h:55
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2926
TupleDesc rd_att
Definition: rel.h:114
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *orig_slot, EState *estate)
Definition: execMain.c:1789
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
TupleConstr * constr
Definition: tupdesc.h:76
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes)
Definition: trigger.c:2239
void list_free(List *list)
Definition: list.c:1133
TupleTableSlot * ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2173
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:384
void ExecSimpleRelationUpdate ( EState estate,
EPQState epqstate,
TupleTableSlot searchslot,
TupleTableSlot slot 
)

Definition at line 420 of file execReplication.c.

References Assert, CheckCmdReplicaIdentity(), CMD_UPDATE, tupleDesc::constr, EState::es_result_relation_info, ExecARUpdateTriggers(), ExecBRUpdateTriggers(), ExecConstraints(), ExecInsertIndexTuples(), ExecMaterializeSlot(), HeapTupleIsHeapOnly, list_free(), NIL, NULL, RelationData::rd_att, RelationData::rd_rel, RELKIND_RELATION, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, simple_heap_update(), HeapTupleData::t_self, TriggerDesc::trig_update_before_row, and TupleTableSlot::tts_tuple.

Referenced by apply_handle_update().

422 {
423  bool skip_tuple = false;
424  HeapTuple tuple;
425  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
426  Relation rel = resultRelInfo->ri_RelationDesc;
427 
428  /* For now we support only tables. */
429  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
430 
432 
433  /* BEFORE ROW INSERT Triggers */
434  if (resultRelInfo->ri_TrigDesc &&
435  resultRelInfo->ri_TrigDesc->trig_update_before_row)
436  {
437  slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
438  &searchslot->tts_tuple->t_self,
439  NULL, slot);
440 
441  if (slot == NULL) /* "do nothing" */
442  skip_tuple = true;
443  }
444 
445  if (!skip_tuple)
446  {
447  List *recheckIndexes = NIL;
448 
449  /* Check the constraints of the tuple */
450  if (rel->rd_att->constr)
451  ExecConstraints(resultRelInfo, slot, slot, estate);
452 
453  /* Store the slot into tuple that we can write. */
454  tuple = ExecMaterializeSlot(slot);
455 
456  /* OK, update the tuple and index entries for it */
457  simple_heap_update(rel, &searchslot->tts_tuple->t_self,
458  slot->tts_tuple);
459 
460  if (resultRelInfo->ri_NumIndices > 0 &&
462  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
463  estate, false, NULL,
464  NIL);
465 
466  /* AFTER ROW UPDATE Triggers */
467  ExecARUpdateTriggers(estate, resultRelInfo,
468  &searchslot->tts_tuple->t_self,
469  NULL, tuple, recheckIndexes);
470 
471  list_free(recheckIndexes);
472  }
473 }
int ri_NumIndices
Definition: execnodes.h:336
#define NIL
Definition: pg_list.h:69
Relation ri_RelationDesc
Definition: execnodes.h:335
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
TupleTableSlot * ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2591
Form_pg_class rd_rel
Definition: rel.h:113
ItemPointerData t_self
Definition: htup.h:65
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes)
Definition: trigger.c:2708
bool trig_update_before_row
Definition: reltrigger.h:60
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:339
TupleDesc rd_att
Definition: rel.h:114
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, TupleTableSlot *orig_slot, EState *estate)
Definition: execMain.c:1789
#define NULL
Definition: c.h:226
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:686
#define Assert(condition)
Definition: c.h:671
TupleConstr * constr
Definition: tupdesc.h:76
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4489
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
void list_free(List *list)
Definition: list.c:1133
HeapTuple tts_tuple
Definition: tuptable.h:120
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:384
bool RelationFindReplTupleByIndex ( Relation  rel,
Oid  idxoid,
LockTupleMode  lockmode,
TupleTableSlot searchslot,
TupleTableSlot outslot 
)

Definition at line 114 of file execReplication.c.

References buf, build_replindex_scan_key(), elog, ereport, errcode(), errmsg(), ERROR, ExecMaterializeSlot(), ExecStoreTuple(), ForwardScanDirection, GetCurrentCommandId(), GetLatestSnapshot(), heap_lock_tuple(), HeapTupleInvisible, HeapTupleMayBeUpdated, HeapTupleUpdated, index_beginscan(), index_close(), index_endscan(), index_getnext(), INDEX_MAX_KEYS, index_open(), index_rescan(), InitDirtySnapshot, InvalidBuffer, ItemPointerCopy, LOG, NoLock, NULL, PopActiveSnapshot(), PushActiveSnapshot(), RelationGetNumberOfAttributes, ReleaseBuffer(), RowExclusiveLock, HeapTupleData::t_self, TransactionIdIsValid, TupleTableSlot::tts_tuple, XactLockTableWait(), XLTW_None, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by apply_handle_delete(), and apply_handle_update().

118 {
119  HeapTuple scantuple;
121  IndexScanDesc scan;
122  SnapshotData snap;
123  TransactionId xwait;
124  Relation idxrel;
125  bool found;
126 
127  /* Open the index.*/
128  idxrel = index_open(idxoid, RowExclusiveLock);
129 
130  /* Start an index scan. */
131  InitDirtySnapshot(snap);
132  scan = index_beginscan(rel, idxrel, &snap,
134  0);
135 
136  /* Build scan key. */
137  build_replindex_scan_key(skey, rel, idxrel, searchslot);
138 
139 retry:
140  found = false;
141 
142  index_rescan(scan, skey, RelationGetNumberOfAttributes(idxrel), NULL, 0);
143 
144  /* Try to find the tuple */
145  if ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL)
146  {
147  found = true;
148  ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
149  ExecMaterializeSlot(outslot);
150 
151  xwait = TransactionIdIsValid(snap.xmin) ?
152  snap.xmin : snap.xmax;
153 
154  /*
155  * If the tuple is locked, wait for locking transaction to finish
156  * and retry.
157  */
158  if (TransactionIdIsValid(xwait))
159  {
161  goto retry;
162  }
163  }
164 
165  /* Found tuple, try to lock it in the lockmode. */
166  if (found)
167  {
168  Buffer buf;
170  HTSU_Result res;
171  HeapTupleData locktup;
172 
173  ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
174 
176 
177  res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false),
178  lockmode,
179  false /* wait */,
180  false /* don't follow updates */,
181  &buf, &hufd);
182  /* the tuple slot already has the buffer pinned */
183  ReleaseBuffer(buf);
184 
186 
187  switch (res)
188  {
190  break;
191  case HeapTupleUpdated:
192  /* XXX: Improve handling here */
193  ereport(LOG,
194  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
195  errmsg("concurrent update, retrying")));
196  goto retry;
197  case HeapTupleInvisible:
198  elog(ERROR, "attempted to lock invisible tuple");
199  default:
200  elog(ERROR, "unexpected heap_lock_tuple status: %u", res);
201  break;
202  }
203  }
204 
205  index_endscan(scan);
206 
207  /* Don't release lock until commit. */
208  index_close(idxrel, NoLock);
209 
210  return found;
211 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
uint32 TransactionId
Definition: c.h:394
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:4578
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:419
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:310
int errcode(int sqlerrcode)
Definition: elog.c:575
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
#define LOG
Definition: elog.h:26
#define ERROR
Definition: elog.h:43
Definition: lmgr.h:26
#define InitDirtySnapshot(snapshotdata)
Definition: tqual.h:100
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
static char * buf
Definition: pg_test_fsync.c:65
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
#define RowExclusiveLock
Definition: lockdefs.h:38
HTSU_Result
Definition: snapshot.h:119
TransactionId xmax
Definition: snapshot.h:67
TransactionId xmin
Definition: snapshot.h:66
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
#define ereport(elevel, rest)
Definition: elog.h:122
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
#define NULL
Definition: c.h:226
#define INDEX_MAX_KEYS
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:375
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
int errmsg(const char *fmt,...)
Definition: elog.c:797
HeapTuple tts_tuple
Definition: tuptable.h:120
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:686
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
static bool build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel, TupleTableSlot *searchslot)
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:659
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:221
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:120
bool RelationFindReplTupleSeq ( Relation  rel,
LockTupleMode  lockmode,
TupleTableSlot searchslot,
TupleTableSlot outslot 
)

Definition at line 267 of file execReplication.c.

References Assert, buf, elog, equalTupleDescs(), ereport, errcode(), errmsg(), ERROR, ExecMaterializeSlot(), ExecStoreTuple(), ForwardScanDirection, GetCurrentCommandId(), GetLatestSnapshot(), heap_beginscan(), heap_endscan(), heap_getnext(), heap_lock_tuple(), heap_rescan(), HeapTupleInvisible, HeapTupleMayBeUpdated, HeapTupleUpdated, InitDirtySnapshot, InvalidBuffer, ItemPointerCopy, LOG, NULL, PopActiveSnapshot(), PushActiveSnapshot(), RelationGetDescr, ReleaseBuffer(), HeapTupleData::t_self, TransactionIdIsValid, TupleTableSlot::tts_tuple, TupleTableSlot::tts_tupleDescriptor, tuple_equals_slot(), XactLockTableWait(), XLTW_None, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by apply_handle_delete(), and apply_handle_update().

269 {
270  HeapTuple scantuple;
271  HeapScanDesc scan;
272  SnapshotData snap;
273  TransactionId xwait;
274  bool found;
275  TupleDesc desc = RelationGetDescr(rel);
276 
277  Assert(equalTupleDescs(desc, outslot->tts_tupleDescriptor));
278 
279  /* Start an index scan. */
280  InitDirtySnapshot(snap);
281  scan = heap_beginscan(rel, &snap, 0, NULL);
282 
283 retry:
284  found = false;
285 
286  heap_rescan(scan, NULL);
287 
288  /* Try to find the tuple */
289  while ((scantuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
290  {
291  if (!tuple_equals_slot(desc, scantuple, searchslot))
292  continue;
293 
294  found = true;
295  ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
296  ExecMaterializeSlot(outslot);
297 
298  xwait = TransactionIdIsValid(snap.xmin) ?
299  snap.xmin : snap.xmax;
300 
301  /*
302  * If the tuple is locked, wait for locking transaction to finish
303  * and retry.
304  */
305  if (TransactionIdIsValid(xwait))
306  {
308  goto retry;
309  }
310  }
311 
312  /* Found tuple, try to lock it in the lockmode. */
313  if (found)
314  {
315  Buffer buf;
317  HTSU_Result res;
318  HeapTupleData locktup;
319 
320  ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
321 
323 
324  res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false),
325  lockmode,
326  false /* wait */,
327  false /* don't follow updates */,
328  &buf, &hufd);
329  /* the tuple slot already has the buffer pinned */
330  ReleaseBuffer(buf);
331 
333 
334  switch (res)
335  {
337  break;
338  case HeapTupleUpdated:
339  /* XXX: Improve handling here */
340  ereport(LOG,
341  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
342  errmsg("concurrent update, retrying")));
343  goto retry;
344  case HeapTupleInvisible:
345  elog(ERROR, "attempted to lock invisible tuple");
346  default:
347  elog(ERROR, "unexpected heap_lock_tuple status: %u", res);
348  break;
349  }
350  }
351 
352  heap_endscan(scan);
353 
354  return found;
355 }
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1581
uint32 TransactionId
Definition: c.h:394
#define RelationGetDescr(relation)
Definition: rel.h:425
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:4578
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:575
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
#define LOG
Definition: elog.h:26
static bool tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
#define ERROR
Definition: elog.h:43
Definition: lmgr.h:26
#define InitDirtySnapshot(snapshotdata)
Definition: tqual.h:100
ItemPointerData t_self
Definition: htup.h:65
static char * buf
Definition: pg_test_fsync.c:65
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
HTSU_Result
Definition: snapshot.h:119
void heap_rescan(HeapScanDesc scan, ScanKey key)
Definition: heapam.c:1518
TransactionId xmax
Definition: snapshot.h:67
TransactionId xmin
Definition: snapshot.h:66
#define ereport(elevel, rest)
Definition: elog.h:122
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1781
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:375
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:352
HeapTuple tts_tuple
Definition: tuptable.h:120
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:686
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1394
int Buffer
Definition: buf.h:23
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:120
static bool tuple_equals_slot ( TupleDesc  desc,
HeapTuple  tup,
TupleTableSlot slot 
)
static

Definition at line 222 of file execReplication.c.

References tupleDesc::attrs, datumIsEqual(), heap_deform_tuple(), MaxTupleAttributeNumber, tupleDesc::natts, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, and values.

Referenced by RelationFindReplTupleSeq().

223 {
225  bool isnull[MaxTupleAttributeNumber];
226  int attrnum;
227  Form_pg_attribute att;
228 
229  heap_deform_tuple(tup, desc, values, isnull);
230 
231  /* Check equality of the attributes. */
232  for (attrnum = 0; attrnum < desc->natts; attrnum++)
233  {
234  /*
235  * If one value is NULL and other is not, then they are certainly not
236  * equal
237  */
238  if (isnull[attrnum] != slot->tts_isnull[attrnum])
239  return false;
240 
241  /*
242  * If both are NULL, they can be considered equal.
243  */
244  if (isnull[attrnum])
245  continue;
246 
247  att = desc->attrs[attrnum];
248  if (!datumIsEqual(values[attrnum], slot->tts_values[attrnum],
249  att->attbyval, att->attlen))
250  return false;
251  }
252 
253  return true;
254 }
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:219
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Datum * tts_values
Definition: tuptable.h:125
int natts
Definition: tupdesc.h:73
bool * tts_isnull
Definition: tuptable.h:126
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
uintptr_t Datum
Definition: postgres.h:374
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:935
static Datum values[MAXATTR]
Definition: bootstrap.c:162