PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
execReplication.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * execReplication.c
4  * miscellaneous executor routines for logical replication
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/backend/executor/execReplication.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/relscan.h"
18 #include "access/transam.h"
19 #include "access/xact.h"
20 #include "commands/trigger.h"
21 #include "executor/executor.h"
22 #include "nodes/nodeFuncs.h"
23 #include "parser/parse_relation.h"
24 #include "parser/parsetree.h"
25 #include "storage/bufmgr.h"
26 #include "storage/lmgr.h"
27 #include "utils/builtins.h"
28 #include "utils/datum.h"
29 #include "utils/lsyscache.h"
30 #include "utils/memutils.h"
31 #include "utils/rel.h"
32 #include "utils/snapmgr.h"
33 #include "utils/syscache.h"
34 #include "utils/typcache.h"
35 #include "utils/tqual.h"
36 
37 
38 /*
39  * Setup a ScanKey for a search in the relation 'rel' for a tuple 'key' that
40  * is setup to match 'rel' (*NOT* idxrel!).
41  *
42  * Returns whether any column contains NULLs.
43  *
44  * This is not generic routine, it expects the idxrel to be replication
45  * identity of a rel and meet all limitations associated with that.
46  */
47 static bool
49  TupleTableSlot *searchslot)
50 {
51  int attoff;
52  bool isnull;
53  Datum indclassDatum;
54  oidvector *opclass;
55  int2vector *indkey = &idxrel->rd_index->indkey;
56  bool hasnulls = false;
57 
59 
60  indclassDatum = SysCacheGetAttr(INDEXRELID, idxrel->rd_indextuple,
61  Anum_pg_index_indclass, &isnull);
62  Assert(!isnull);
63  opclass = (oidvector *) DatumGetPointer(indclassDatum);
64 
65  /* Build scankey for every attribute in the index. */
66  for (attoff = 0; attoff < RelationGetNumberOfAttributes(idxrel); attoff++)
67  {
68  Oid operator;
69  Oid opfamily;
70  RegProcedure regop;
71  int pkattno = attoff + 1;
72  int mainattno = indkey->values[attoff];
73  Oid optype = get_opclass_input_type(opclass->values[attoff]);
74 
75  /*
76  * Load the operator info. We need this to get the equality operator
77  * function for the scan key.
78  */
79  opfamily = get_opclass_family(opclass->values[attoff]);
80 
81  operator = get_opfamily_member(opfamily, optype,
82  optype,
84 
85  if (!OidIsValid(operator))
86  elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
87  BTEqualStrategyNumber, optype, optype, opfamily);
88 
89  regop = get_opcode(operator);
90 
91  /* Initialize the scankey. */
92  ScanKeyInit(&skey[attoff],
93  pkattno,
95  regop,
96  searchslot->tts_values[mainattno - 1]);
97 
98  /* Check for null value. */
99  if (searchslot->tts_isnull[mainattno - 1])
100  {
101  hasnulls = true;
102  skey[attoff].sk_flags |= SK_ISNULL;
103  }
104  }
105 
106  return hasnulls;
107 }
108 
109 /*
110  * Search the relation 'rel' for tuple using the index.
111  *
112  * If a matching tuple is found, lock it with lockmode, fill the slot with its
113  * contents, and return true. Return false otherwise.
114  */
115 bool
117  LockTupleMode lockmode,
118  TupleTableSlot *searchslot,
119  TupleTableSlot *outslot)
120 {
121  HeapTuple scantuple;
123  IndexScanDesc scan;
124  SnapshotData snap;
125  TransactionId xwait;
126  Relation idxrel;
127  bool found;
128 
129  /* Open the index. */
130  idxrel = index_open(idxoid, RowExclusiveLock);
131 
132  /* Start an index scan. */
133  InitDirtySnapshot(snap);
134  scan = index_beginscan(rel, idxrel, &snap,
136  0);
137 
138  /* Build scan key. */
139  build_replindex_scan_key(skey, rel, idxrel, searchslot);
140 
141 retry:
142  found = false;
143 
144  index_rescan(scan, skey, RelationGetNumberOfAttributes(idxrel), NULL, 0);
145 
146  /* Try to find the tuple */
147  if ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL)
148  {
149  found = true;
150  ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
151  ExecMaterializeSlot(outslot);
152 
153  xwait = TransactionIdIsValid(snap.xmin) ?
154  snap.xmin : snap.xmax;
155 
156  /*
157  * If the tuple is locked, wait for locking transaction to finish and
158  * retry.
159  */
160  if (TransactionIdIsValid(xwait))
161  {
163  goto retry;
164  }
165  }
166 
167  /* Found tuple, try to lock it in the lockmode. */
168  if (found)
169  {
170  Buffer buf;
172  HTSU_Result res;
173  HeapTupleData locktup;
174 
175  ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
176 
178 
179  res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false),
180  lockmode,
182  false /* don't follow updates */ ,
183  &buf, &hufd);
184  /* the tuple slot already has the buffer pinned */
185  ReleaseBuffer(buf);
186 
188 
189  switch (res)
190  {
192  break;
193  case HeapTupleUpdated:
194  /* XXX: Improve handling here */
195  ereport(LOG,
196  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
197  errmsg("concurrent update, retrying")));
198  goto retry;
199  case HeapTupleInvisible:
200  elog(ERROR, "attempted to lock invisible tuple");
201  default:
202  elog(ERROR, "unexpected heap_lock_tuple status: %u", res);
203  break;
204  }
205  }
206 
207  index_endscan(scan);
208 
209  /* Don't release lock until commit. */
210  index_close(idxrel, NoLock);
211 
212  return found;
213 }
214 
215 /*
216  * Compare the tuple and slot and check if they have equal values.
217  *
218  * We use binary datum comparison which might return false negatives but
219  * that's the best we can do here as there may be multiple notions of
220  * equality for the data types and table columns don't specify which one
221  * to use.
222  */
223 static bool
225 {
227  bool isnull[MaxTupleAttributeNumber];
228  int attrnum;
229 
230  heap_deform_tuple(tup, desc, values, isnull);
231 
232  /* Check equality of the attributes. */
233  for (attrnum = 0; attrnum < desc->natts; attrnum++)
234  {
235  Form_pg_attribute att;
236  TypeCacheEntry *typentry;
237 
238  /*
239  * If one value is NULL and other is not, then they are certainly not
240  * equal
241  */
242  if (isnull[attrnum] != slot->tts_isnull[attrnum])
243  return false;
244 
245  /*
246  * If both are NULL, they can be considered equal.
247  */
248  if (isnull[attrnum])
249  continue;
250 
251  att = desc->attrs[attrnum];
252 
253  typentry = lookup_type_cache(att->atttypid, TYPECACHE_EQ_OPR_FINFO);
254  if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
255  ereport(ERROR,
256  (errcode(ERRCODE_UNDEFINED_FUNCTION),
257  errmsg("could not identify an equality operator for type %s",
258  format_type_be(att->atttypid))));
259 
260  if (!DatumGetBool(FunctionCall2(&typentry->eq_opr_finfo,
261  values[attrnum],
262  slot->tts_values[attrnum])))
263  return false;
264  }
265 
266  return true;
267 }
268 
269 /*
270  * Search the relation 'rel' for tuple using the sequential scan.
271  *
272  * If a matching tuple is found, lock it with lockmode, fill the slot with its
273  * contents, and return true. Return false otherwise.
274  *
275  * Note that this stops on the first matching tuple.
276  *
277  * This can obviously be quite slow on tables that have more than few rows.
278  */
279 bool
281  TupleTableSlot *searchslot, TupleTableSlot *outslot)
282 {
283  HeapTuple scantuple;
284  HeapScanDesc scan;
285  SnapshotData snap;
286  TransactionId xwait;
287  bool found;
288  TupleDesc desc = RelationGetDescr(rel);
289 
290  Assert(equalTupleDescs(desc, outslot->tts_tupleDescriptor));
291 
292  /* Start an index scan. */
293  InitDirtySnapshot(snap);
294  scan = heap_beginscan(rel, &snap, 0, NULL);
295 
296 retry:
297  found = false;
298 
299  heap_rescan(scan, NULL);
300 
301  /* Try to find the tuple */
302  while ((scantuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
303  {
304  if (!tuple_equals_slot(desc, scantuple, searchslot))
305  continue;
306 
307  found = true;
308  ExecStoreTuple(scantuple, outslot, InvalidBuffer, false);
309  ExecMaterializeSlot(outslot);
310 
311  xwait = TransactionIdIsValid(snap.xmin) ?
312  snap.xmin : snap.xmax;
313 
314  /*
315  * If the tuple is locked, wait for locking transaction to finish and
316  * retry.
317  */
318  if (TransactionIdIsValid(xwait))
319  {
321  goto retry;
322  }
323  }
324 
325  /* Found tuple, try to lock it in the lockmode. */
326  if (found)
327  {
328  Buffer buf;
330  HTSU_Result res;
331  HeapTupleData locktup;
332 
333  ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self);
334 
336 
337  res = heap_lock_tuple(rel, &locktup, GetCurrentCommandId(false),
338  lockmode,
340  false /* don't follow updates */ ,
341  &buf, &hufd);
342  /* the tuple slot already has the buffer pinned */
343  ReleaseBuffer(buf);
344 
346 
347  switch (res)
348  {
350  break;
351  case HeapTupleUpdated:
352  /* XXX: Improve handling here */
353  ereport(LOG,
354  (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
355  errmsg("concurrent update, retrying")));
356  goto retry;
357  case HeapTupleInvisible:
358  elog(ERROR, "attempted to lock invisible tuple");
359  default:
360  elog(ERROR, "unexpected heap_lock_tuple status: %u", res);
361  break;
362  }
363  }
364 
365  heap_endscan(scan);
366 
367  return found;
368 }
369 
370 /*
371  * Insert tuple represented in the slot to the relation, update the indexes,
372  * and execute any constraints and per-row triggers.
373  *
374  * Caller is responsible for opening the indexes.
375  */
376 void
378 {
379  bool skip_tuple = false;
380  HeapTuple tuple;
381  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
382  Relation rel = resultRelInfo->ri_RelationDesc;
383 
384  /* For now we support only tables. */
385  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
386 
388 
389  /* BEFORE ROW INSERT Triggers */
390  if (resultRelInfo->ri_TrigDesc &&
391  resultRelInfo->ri_TrigDesc->trig_insert_before_row)
392  {
393  slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
394 
395  if (slot == NULL) /* "do nothing" */
396  skip_tuple = true;
397  }
398 
399  if (!skip_tuple)
400  {
401  List *recheckIndexes = NIL;
402 
403  /* Check the constraints of the tuple */
404  if (rel->rd_att->constr)
405  ExecConstraints(resultRelInfo, slot, estate);
406 
407  /* Store the slot into tuple that we can inspect. */
408  tuple = ExecMaterializeSlot(slot);
409 
410  /* OK, store the tuple and create index entries for it */
411  simple_heap_insert(rel, tuple);
412 
413  if (resultRelInfo->ri_NumIndices > 0)
414  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
415  estate, false, NULL,
416  NIL);
417 
418  /* AFTER ROW INSERT Triggers */
419  ExecARInsertTriggers(estate, resultRelInfo, tuple,
420  recheckIndexes, NULL);
421 
422  /*
423  * XXX we should in theory pass a TransitionCaptureState object to the
424  * above to capture transition tuples, but after statement triggers
425  * don't actually get fired by replication yet anyway
426  */
427 
428  list_free(recheckIndexes);
429  }
430 }
431 
432 /*
433  * Find the searchslot tuple and update it with data in the slot,
434  * update the indexes, and execute any constraints and per-row triggers.
435  *
436  * Caller is responsible for opening the indexes.
437  */
438 void
440  TupleTableSlot *searchslot, TupleTableSlot *slot)
441 {
442  bool skip_tuple = false;
443  HeapTuple tuple;
444  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
445  Relation rel = resultRelInfo->ri_RelationDesc;
446 
447  /* For now we support only tables. */
448  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
449 
451 
452  /* BEFORE ROW INSERT Triggers */
453  if (resultRelInfo->ri_TrigDesc &&
454  resultRelInfo->ri_TrigDesc->trig_update_before_row)
455  {
456  slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
457  &searchslot->tts_tuple->t_self,
458  NULL, slot);
459 
460  if (slot == NULL) /* "do nothing" */
461  skip_tuple = true;
462  }
463 
464  if (!skip_tuple)
465  {
466  List *recheckIndexes = NIL;
467 
468  /* Check the constraints of the tuple */
469  if (rel->rd_att->constr)
470  ExecConstraints(resultRelInfo, slot, estate);
471 
472  /* Store the slot into tuple that we can write. */
473  tuple = ExecMaterializeSlot(slot);
474 
475  /* OK, update the tuple and index entries for it */
476  simple_heap_update(rel, &searchslot->tts_tuple->t_self,
477  slot->tts_tuple);
478 
479  if (resultRelInfo->ri_NumIndices > 0 &&
481  recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
482  estate, false, NULL,
483  NIL);
484 
485  /* AFTER ROW UPDATE Triggers */
486  ExecARUpdateTriggers(estate, resultRelInfo,
487  &searchslot->tts_tuple->t_self,
488  NULL, tuple, recheckIndexes, NULL);
489 
490  list_free(recheckIndexes);
491  }
492 }
493 
494 /*
495  * Find the searchslot tuple and delete it, and execute any constraints
496  * and per-row triggers.
497  *
498  * Caller is responsible for opening the indexes.
499  */
500 void
502  TupleTableSlot *searchslot)
503 {
504  bool skip_tuple = false;
505  ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
506  Relation rel = resultRelInfo->ri_RelationDesc;
507 
508  /* For now we support only tables. */
509  Assert(rel->rd_rel->relkind == RELKIND_RELATION);
510 
512 
513  /* BEFORE ROW INSERT Triggers */
514  if (resultRelInfo->ri_TrigDesc &&
515  resultRelInfo->ri_TrigDesc->trig_update_before_row)
516  {
517  skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
518  &searchslot->tts_tuple->t_self,
519  NULL);
520  }
521 
522  if (!skip_tuple)
523  {
524  List *recheckIndexes = NIL;
525 
526  /* OK, delete the tuple */
527  simple_heap_delete(rel, &searchslot->tts_tuple->t_self);
528 
529  /* AFTER ROW DELETE Triggers */
530  ExecARDeleteTriggers(estate, resultRelInfo,
531  &searchslot->tts_tuple->t_self, NULL, NULL);
532 
533  list_free(recheckIndexes);
534  }
535 }
536 
537 /*
538  * Check if command can be executed with current replica identity.
539  */
540 void
542 {
543  PublicationActions *pubactions;
544 
545  /* We only need to do checks for UPDATE and DELETE. */
546  if (cmd != CMD_UPDATE && cmd != CMD_DELETE)
547  return;
548 
549  /* If relation has replica identity we are always good. */
550  if (rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL ||
552  return;
553 
554  /*
555  * This is either UPDATE OR DELETE and there is no replica identity.
556  *
557  * Check if the table publishes UPDATES or DELETES.
558  */
559  pubactions = GetRelationPublicationActions(rel);
560  if (cmd == CMD_UPDATE && pubactions->pubupdate)
561  ereport(ERROR,
562  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
563  errmsg("cannot update table \"%s\" because it does not have replica identity and publishes updates",
565  errhint("To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.")));
566  else if (cmd == CMD_DELETE && pubactions->pubdelete)
567  ereport(ERROR,
568  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
569  errmsg("cannot delete from table \"%s\" because it does not have replica identity and publishes deletes",
571  errhint("To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE.")));
572 }
573 
574 
575 /*
576  * Check if we support writing into specific relkind.
577  *
578  * The nspname and relname are only needed for error reporting.
579  */
580 void
581 CheckSubscriptionRelkind(char relkind, const char *nspname,
582  const char *relname)
583 {
584  /*
585  * We currently only support writing to regular tables.
586  */
587  if (relkind != RELKIND_RELATION)
588  ereport(ERROR,
589  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
590  errmsg("logical replication target relation \"%s.%s\" is not a table",
591  nspname, relname)));
592 }
void ExecSimpleRelationInsert(EState *estate, TupleTableSlot *slot)
int ri_NumIndices
Definition: execnodes.h:357
#define NIL
Definition: pg_list.h:69
Definition: c.h:478
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
Relation ri_RelationDesc
Definition: execnodes.h:354
int errhint(const char *fmt,...)
Definition: elog.c:987
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1578
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4676
List * ExecInsertIndexTuples(TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool noDupErr, bool *specConflict, List *arbiterIndexes)
Definition: execIndexing.c:271
uint32 TransactionId
Definition: c.h:397
#define MaxTupleAttributeNumber
Definition: htup_details.h:33
#define RelationGetDescr(relation)
Definition: rel.h:428
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
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:422
#define TYPECACHE_EQ_OPR_FINFO
Definition: typcache.h:115
regproc RegProcedure
Definition: c.h:395
TupleTableSlot * ExecBRUpdateTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TupleTableSlot *slot)
Definition: trigger.c:2773
Form_pg_attribute * attrs
Definition: tupdesc.h:74
void ExecConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1913
#define FunctionCall2(flinfo, arg1, arg2)
Definition: fmgr.h:604
#define Anum_pg_index_indclass
Definition: pg_index.h:89
#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
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
void ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo, HeapTuple trigtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2413
Datum * tts_values
Definition: tuptable.h:125
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
#define LOG
Definition: elog.h:26
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
bool RelationFindReplTupleByIndex(Relation rel, Oid idxoid, LockTupleMode lockmode, TupleTableSlot *searchslot, TupleTableSlot *outslot)
int natts
Definition: tupdesc.h:73
struct HeapTupleData * rd_indextuple
Definition: rel.h:161
static bool tuple_equals_slot(TupleDesc desc, HeapTuple tup, TupleTableSlot *slot)
void ExecARDeleteTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, TransitionCaptureState *transition_capture)
Definition: trigger.c:2626
LockTupleMode
Definition: heapam.h:38
Form_pg_index rd_index
Definition: rel.h:159
#define REPLICA_IDENTITY_FULL
Definition: pg_class.h:179
#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:66
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
bool * tts_isnull
Definition: tuptable.h:126
void ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, TupleTableSlot *searchslot)
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:486
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
#define DatumGetBool(X)
Definition: postgres.h:399
bool trig_update_before_row
Definition: reltrigger.h:60
void heap_rescan(HeapScanDesc scan, ScanKey key)
Definition: heapam.c:1515
HTSU_Result
Definition: snapshot.h:119
#define RelationGetRelationName(relation)
Definition: rel.h:436
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
TransactionId xmax
Definition: snapshot.h:67
void CheckSubscriptionRelkind(char relkind, const char *nspname, const char *relname)
TransactionId xmin
Definition: snapshot.h:66
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:340
#define SK_ISNULL
Definition: skey.h:115
#define ereport(elevel, rest)
Definition: elog.h:122
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:366
void ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple, HeapTuple newtuple, List *recheckIndexes, TransitionCaptureState *transition_capture)
Definition: trigger.c:2890
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
Definition: c.h:467
bool trig_insert_before_row
Definition: reltrigger.h:55
uintptr_t Datum
Definition: postgres.h:372
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
Oid simple_heap_insert(Relation relation, HeapTuple tup)
Definition: heapam.c:2939
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1794
TupleDesc rd_att
Definition: rel.h:115
FmgrInfo eq_opr_finfo
Definition: typcache.h:67
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:191
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
Oid fn_oid
Definition: fmgr.h:59
struct PublicationActions * GetRelationPublicationActions(Relation relation)
Definition: relcache.c:5172
bool ExecBRDeleteTriggers(EState *estate, EPQState *epqstate, ResultRelInfo *relinfo, ItemPointer tupleid, HeapTuple fdw_trigtuple)
Definition: trigger.c:2557
int sk_flags
Definition: skey.h:66
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
#define NULL
Definition: c.h:229
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:686
#define Assert(condition)
Definition: c.h:675
TupleConstr * constr
Definition: tupdesc.h:76
#define INDEX_MAX_KEYS
void simple_heap_delete(Relation relation, ItemPointer tid)
Definition: heapam.c:3398
void simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
Definition: heapam.c:4451
HeapTuple ExecMaterializeSlot(TupleTableSlot *slot)
Definition: execTuples.c:725
int16 values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:475
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1047
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
#define DatumGetPointer(X)
Definition: postgres.h:555
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:933
static Datum values[MAXATTR]
Definition: bootstrap.c:163
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
bool RelationFindReplTupleSeq(Relation rel, LockTupleMode lockmode, TupleTableSlot *searchslot, TupleTableSlot *outslot)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:354
TupleTableSlot * ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo, TupleTableSlot *slot)
Definition: trigger.c:2347
HeapTuple tts_tuple
Definition: tuptable.h:120
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:687
#define elog
Definition: elog.h:219
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1391
int Buffer
Definition: buf.h:23
static bool build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel, TupleTableSlot *searchslot)
#define RelationGetRelid(relation)
Definition: rel.h:416
CmdType
Definition: nodes.h:649
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, TupleTableSlot *searchslot, TupleTableSlot *slot)
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:139
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1069
ResultRelInfo * es_result_relation_info
Definition: execnodes.h:443