PostgreSQL Source Code git master
conflict.c File Reference
#include "postgres.h"
#include "access/commit_ts.h"
#include "access/tableam.h"
#include "executor/executor.h"
#include "pgstat.h"
#include "replication/conflict.h"
#include "replication/worker_internal.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
Include dependency graph for conflict.c:

Go to the source code of this file.

Functions

static int errcode_apply_conflict (ConflictType type)
 
static void errdetail_apply_conflict (EState *estate, ResultRelInfo *relinfo, ConflictType type, TupleTableSlot *searchslot, TupleTableSlot *localslot, TupleTableSlot *remoteslot, Oid indexoid, TransactionId localxmin, RepOriginId localorigin, TimestampTz localts, StringInfo err_msg)
 
static char * build_tuple_value_details (EState *estate, ResultRelInfo *relinfo, ConflictType type, TupleTableSlot *searchslot, TupleTableSlot *localslot, TupleTableSlot *remoteslot, Oid indexoid)
 
static char * build_index_value_desc (EState *estate, Relation localrel, TupleTableSlot *slot, Oid indexoid)
 
bool GetTupleTransactionInfo (TupleTableSlot *localslot, TransactionId *xmin, RepOriginId *localorigin, TimestampTz *localts)
 
void ReportApplyConflict (EState *estate, ResultRelInfo *relinfo, int elevel, ConflictType type, TupleTableSlot *searchslot, TupleTableSlot *remoteslot, List *conflicttuples)
 
void InitConflictIndexes (ResultRelInfo *relInfo)
 

Variables

static const char *const ConflictTypeNames []
 

Function Documentation

◆ build_index_value_desc()

static char * build_index_value_desc ( EState estate,
Relation  localrel,
TupleTableSlot slot,
Oid  indexoid 
)
static

Definition at line 483 of file conflict.c.

485{
486 char *index_value;
487 Relation indexDesc;
489 bool isnull[INDEX_MAX_KEYS];
490 TupleTableSlot *tableslot = slot;
491
492 if (!tableslot)
493 return NULL;
494
496
497 indexDesc = index_open(indexoid, NoLock);
498
499 /*
500 * If the slot is a virtual slot, copy it into a heap tuple slot as
501 * FormIndexDatum only works with heap tuple slots.
502 */
503 if (TTS_IS_VIRTUAL(slot))
504 {
505 tableslot = table_slot_create(localrel, &estate->es_tupleTable);
506 tableslot = ExecCopySlot(tableslot, slot);
507 }
508
509 /*
510 * Initialize ecxt_scantuple for potential use in FormIndexDatum when
511 * index expressions are present.
512 */
513 GetPerTupleExprContext(estate)->ecxt_scantuple = tableslot;
514
515 /*
516 * The values/nulls arrays passed to BuildIndexValueDescription should be
517 * the results of FormIndexDatum, which are the "raw" input to the index
518 * AM.
519 */
520 FormIndexDatum(BuildIndexInfo(indexDesc), tableslot, estate, values, isnull);
521
522 index_value = BuildIndexValueDescription(indexDesc, values, isnull);
523
524 index_close(indexDesc, NoLock);
525
526 return index_value;
527}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define GetPerTupleExprContext(estate)
Definition: executor.h:656
char * BuildIndexValueDescription(Relation indexRelation, const Datum *values, const bool *isnull)
Definition: genam.c:178
Assert(PointerIsAligned(start, uint64))
IndexInfo * BuildIndexInfo(Relation index)
Definition: index.c:2428
void FormIndexDatum(IndexInfo *indexInfo, TupleTableSlot *slot, EState *estate, Datum *values, bool *isnull)
Definition: index.c:2730
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
Definition: lmgr.c:351
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define INDEX_MAX_KEYS
uint64_t Datum
Definition: postgres.h:70
List * es_tupleTable
Definition: execnodes.h:712
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92
#define TTS_IS_VIRTUAL(slot)
Definition: tuptable.h:237
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:524

References Assert(), BuildIndexInfo(), BuildIndexValueDescription(), CheckRelationOidLockedByMe(), EState::es_tupleTable, ExecCopySlot(), FormIndexDatum(), GetPerTupleExprContext, index_close(), INDEX_MAX_KEYS, index_open(), NoLock, RowExclusiveLock, table_slot_create(), TTS_IS_VIRTUAL, and values.

Referenced by build_tuple_value_details().

◆ build_tuple_value_details()

static char * build_tuple_value_details ( EState estate,
ResultRelInfo relinfo,
ConflictType  type,
TupleTableSlot searchslot,
TupleTableSlot localslot,
TupleTableSlot remoteslot,
Oid  indexoid 
)
static

Definition at line 340 of file conflict.c.

346{
347 Relation localrel = relinfo->ri_RelationDesc;
348 Oid relid = RelationGetRelid(localrel);
349 TupleDesc tupdesc = RelationGetDescr(localrel);
350 StringInfoData tuple_value;
351 char *desc = NULL;
352
353 Assert(searchslot || localslot || remoteslot);
354
355 initStringInfo(&tuple_value);
356
357 /*
358 * Report the conflicting key values in the case of a unique constraint
359 * violation.
360 */
363 {
364 Assert(OidIsValid(indexoid) && localslot);
365
366 desc = build_index_value_desc(estate, localrel, localslot, indexoid);
367
368 if (desc)
369 appendStringInfo(&tuple_value, _("Key %s"), desc);
370 }
371
372 if (localslot)
373 {
374 /*
375 * The 'modifiedCols' only applies to the new tuple, hence we pass
376 * NULL for the existing local row.
377 */
378 desc = ExecBuildSlotValueDescription(relid, localslot, tupdesc,
379 NULL, 64);
380
381 if (desc)
382 {
383 if (tuple_value.len > 0)
384 {
385 appendStringInfoString(&tuple_value, "; ");
386 appendStringInfo(&tuple_value, _("existing local row %s"),
387 desc);
388 }
389 else
390 {
391 appendStringInfo(&tuple_value, _("Existing local row %s"),
392 desc);
393 }
394 }
395 }
396
397 if (remoteslot)
398 {
399 Bitmapset *modifiedCols;
400
401 /*
402 * Although logical replication doesn't maintain the bitmap for the
403 * columns being inserted, we still use it to create 'modifiedCols'
404 * for consistency with other calls to ExecBuildSlotValueDescription.
405 *
406 * Note that generated columns are formed locally on the subscriber.
407 */
408 modifiedCols = bms_union(ExecGetInsertedCols(relinfo, estate),
409 ExecGetUpdatedCols(relinfo, estate));
410 desc = ExecBuildSlotValueDescription(relid, remoteslot, tupdesc,
411 modifiedCols, 64);
412
413 if (desc)
414 {
415 if (tuple_value.len > 0)
416 {
417 appendStringInfoString(&tuple_value, "; ");
418 appendStringInfo(&tuple_value, _("remote row %s"), desc);
419 }
420 else
421 {
422 appendStringInfo(&tuple_value, _("Remote row %s"), desc);
423 }
424 }
425 }
426
427 if (searchslot)
428 {
429 /*
430 * Note that while index other than replica identity may be used (see
431 * IsIndexUsableForReplicaIdentityFull for details) to find the tuple
432 * when applying update or delete, such an index scan may not result
433 * in a unique tuple and we still compare the complete tuple in such
434 * cases, thus such indexes are not used here.
435 */
436 Oid replica_index = GetRelationIdentityOrPK(localrel);
437
439
440 /*
441 * If the table has a valid replica identity index, build the index
442 * key value string. Otherwise, construct the full tuple value for
443 * REPLICA IDENTITY FULL cases.
444 */
445 if (OidIsValid(replica_index))
446 desc = build_index_value_desc(estate, localrel, searchslot, replica_index);
447 else
448 desc = ExecBuildSlotValueDescription(relid, searchslot, tupdesc, NULL, 64);
449
450 if (desc)
451 {
452 if (tuple_value.len > 0)
453 {
454 appendStringInfoString(&tuple_value, "; ");
455 appendStringInfo(&tuple_value, OidIsValid(replica_index)
456 ? _("replica identity %s")
457 : _("replica identity full %s"), desc);
458 }
459 else
460 {
461 appendStringInfo(&tuple_value, OidIsValid(replica_index)
462 ? _("Replica identity %s")
463 : _("Replica identity full %s"), desc);
464 }
465 }
466 }
467
468 if (tuple_value.len == 0)
469 return NULL;
470
471 appendStringInfoChar(&tuple_value, '.');
472 return tuple_value.data;
473}
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
#define OidIsValid(objectId)
Definition: c.h:777
static char * build_index_value_desc(EState *estate, Relation localrel, TupleTableSlot *slot, Oid indexoid)
Definition: conflict.c:483
@ CT_MULTIPLE_UNIQUE_CONFLICTS
Definition: conflict.h:55
@ CT_INSERT_EXISTS
Definition: conflict.h:34
@ CT_UPDATE_EXISTS
Definition: conflict.h:40
#define _(x)
Definition: elog.c:91
char * ExecBuildSlotValueDescription(Oid reloid, TupleTableSlot *slot, TupleDesc tupdesc, Bitmapset *modifiedCols, int maxfieldlen)
Definition: execMain.c:2391
Bitmapset * ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1361
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1382
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetRelid(relation)
Definition: rel.h:515
#define RelationGetDescr(relation)
Definition: rel.h:541
Oid GetRelationIdentityOrPK(Relation rel)
Definition: relation.c:904
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
Relation ri_RelationDesc
Definition: execnodes.h:480
const char * type

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), bms_union(), build_index_value_desc(), CT_INSERT_EXISTS, CT_MULTIPLE_UNIQUE_CONFLICTS, CT_UPDATE_EXISTS, StringInfoData::data, ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), GetRelationIdentityOrPK(), initStringInfo(), StringInfoData::len, OidIsValid, RelationGetDescr, RelationGetRelid, ResultRelInfo::ri_RelationDesc, and type.

Referenced by errdetail_apply_conflict().

◆ errcode_apply_conflict()

static int errcode_apply_conflict ( ConflictType  type)
static

Definition at line 169 of file conflict.c.

170{
171 switch (type)
172 {
173 case CT_INSERT_EXISTS:
174 case CT_UPDATE_EXISTS:
176 return errcode(ERRCODE_UNIQUE_VIOLATION);
183 }
184
185 Assert(false);
186 return 0; /* silence compiler warning */
187}
@ CT_UPDATE_DELETED
Definition: conflict.h:43
@ CT_DELETE_MISSING
Definition: conflict.h:52
@ CT_UPDATE_ORIGIN_DIFFERS
Definition: conflict.h:37
@ CT_UPDATE_MISSING
Definition: conflict.h:46
@ CT_DELETE_ORIGIN_DIFFERS
Definition: conflict.h:49
int errcode(int sqlerrcode)
Definition: elog.c:863
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:77

References Assert(), CT_DELETE_MISSING, CT_DELETE_ORIGIN_DIFFERS, CT_INSERT_EXISTS, CT_MULTIPLE_UNIQUE_CONFLICTS, CT_UPDATE_DELETED, CT_UPDATE_EXISTS, CT_UPDATE_MISSING, CT_UPDATE_ORIGIN_DIFFERS, errcode(), ERRCODE_T_R_SERIALIZATION_FAILURE, and type.

Referenced by ReportApplyConflict().

◆ errdetail_apply_conflict()

static void errdetail_apply_conflict ( EState estate,
ResultRelInfo relinfo,
ConflictType  type,
TupleTableSlot searchslot,
TupleTableSlot localslot,
TupleTableSlot remoteslot,
Oid  indexoid,
TransactionId  localxmin,
RepOriginId  localorigin,
TimestampTz  localts,
StringInfo  err_msg 
)
static

Definition at line 200 of file conflict.c.

206{
207 StringInfoData err_detail;
208 char *val_desc;
209 char *origin_name;
210
211 initStringInfo(&err_detail);
212
213 /* First, construct a detailed message describing the type of conflict */
214 switch (type)
215 {
216 case CT_INSERT_EXISTS:
217 case CT_UPDATE_EXISTS:
219 Assert(OidIsValid(indexoid) &&
221
222 if (localts)
223 {
224 if (localorigin == InvalidRepOriginId)
225 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified locally in transaction %u at %s."),
226 get_rel_name(indexoid),
227 localxmin, timestamptz_to_str(localts));
228 else if (replorigin_by_oid(localorigin, true, &origin_name))
229 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified by origin \"%s\" in transaction %u at %s."),
230 get_rel_name(indexoid), origin_name,
231 localxmin, timestamptz_to_str(localts));
232
233 /*
234 * The origin that modified this row has been removed. This
235 * can happen if the origin was created by a different apply
236 * worker and its associated subscription and origin were
237 * dropped after updating the row, or if the origin was
238 * manually dropped by the user.
239 */
240 else
241 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified by a non-existent origin in transaction %u at %s."),
242 get_rel_name(indexoid),
243 localxmin, timestamptz_to_str(localts));
244 }
245 else
246 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified in transaction %u."),
247 get_rel_name(indexoid), localxmin);
248
249 break;
250
252 if (localorigin == InvalidRepOriginId)
253 appendStringInfo(&err_detail, _("Updating the row that was modified locally in transaction %u at %s."),
254 localxmin, timestamptz_to_str(localts));
255 else if (replorigin_by_oid(localorigin, true, &origin_name))
256 appendStringInfo(&err_detail, _("Updating the row that was modified by a different origin \"%s\" in transaction %u at %s."),
257 origin_name, localxmin, timestamptz_to_str(localts));
258
259 /* The origin that modified this row has been removed. */
260 else
261 appendStringInfo(&err_detail, _("Updating the row that was modified by a non-existent origin in transaction %u at %s."),
262 localxmin, timestamptz_to_str(localts));
263
264 break;
265
267 if (localts)
268 {
269 if (localorigin == InvalidRepOriginId)
270 appendStringInfo(&err_detail, _("The row to be updated was deleted locally in transaction %u at %s."),
271 localxmin, timestamptz_to_str(localts));
272 else if (replorigin_by_oid(localorigin, true, &origin_name))
273 appendStringInfo(&err_detail, _("The row to be updated was deleted by a different origin \"%s\" in transaction %u at %s."),
274 origin_name, localxmin, timestamptz_to_str(localts));
275
276 /* The origin that modified this row has been removed. */
277 else
278 appendStringInfo(&err_detail, _("The row to be updated was deleted by a non-existent origin in transaction %u at %s."),
279 localxmin, timestamptz_to_str(localts));
280 }
281 else
282 appendStringInfo(&err_detail, _("The row to be updated was deleted."));
283
284 break;
285
287 appendStringInfoString(&err_detail, _("Could not find the row to be updated."));
288 break;
289
291 if (localorigin == InvalidRepOriginId)
292 appendStringInfo(&err_detail, _("Deleting the row that was modified locally in transaction %u at %s."),
293 localxmin, timestamptz_to_str(localts));
294 else if (replorigin_by_oid(localorigin, true, &origin_name))
295 appendStringInfo(&err_detail, _("Deleting the row that was modified by a different origin \"%s\" in transaction %u at %s."),
296 origin_name, localxmin, timestamptz_to_str(localts));
297
298 /* The origin that modified this row has been removed. */
299 else
300 appendStringInfo(&err_detail, _("Deleting the row that was modified by a non-existent origin in transaction %u at %s."),
301 localxmin, timestamptz_to_str(localts));
302
303 break;
304
306 appendStringInfoString(&err_detail, _("Could not find the row to be deleted."));
307 break;
308 }
309
310 Assert(err_detail.len > 0);
311
312 val_desc = build_tuple_value_details(estate, relinfo, type, searchslot,
313 localslot, remoteslot, indexoid);
314
315 /*
316 * Next, append the key values, existing local row, remote row, and
317 * replica identity columns after the message.
318 */
319 if (val_desc)
320 appendStringInfo(&err_detail, "\n%s", val_desc);
321
322 /*
323 * Insert a blank line to visually separate the new detail line from the
324 * existing ones.
325 */
326 if (err_msg->len > 0)
327 appendStringInfoChar(err_msg, '\n');
328
329 appendStringInfoString(err_msg, err_detail.data);
330}
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1862
static char * build_tuple_value_details(EState *estate, ResultRelInfo *relinfo, ConflictType type, TupleTableSlot *searchslot, TupleTableSlot *localslot, TupleTableSlot *remoteslot, Oid indexoid)
Definition: conflict.c:340
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
bool replorigin_by_oid(RepOriginId roident, bool missing_ok, char **roname)
Definition: origin.c:493
#define InvalidRepOriginId
Definition: origin.h:33

References _, appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), build_tuple_value_details(), CheckRelationOidLockedByMe(), CT_DELETE_MISSING, CT_DELETE_ORIGIN_DIFFERS, CT_INSERT_EXISTS, CT_MULTIPLE_UNIQUE_CONFLICTS, CT_UPDATE_DELETED, CT_UPDATE_EXISTS, CT_UPDATE_MISSING, CT_UPDATE_ORIGIN_DIFFERS, StringInfoData::data, get_rel_name(), initStringInfo(), InvalidRepOriginId, StringInfoData::len, OidIsValid, replorigin_by_oid(), RowExclusiveLock, timestamptz_to_str(), and type.

Referenced by ReportApplyConflict().

◆ GetTupleTransactionInfo()

bool GetTupleTransactionInfo ( TupleTableSlot localslot,
TransactionId xmin,
RepOriginId localorigin,
TimestampTz localts 
)

Definition at line 63 of file conflict.c.

65{
66 Datum xminDatum;
67 bool isnull;
68
70 &isnull);
71 *xmin = DatumGetTransactionId(xminDatum);
72 Assert(!isnull);
73
74 /*
75 * The commit timestamp data is not available if track_commit_timestamp is
76 * disabled.
77 */
79 {
80 *localorigin = InvalidRepOriginId;
81 *localts = 0;
82 return false;
83 }
84
85 return TransactionIdGetCommitTsData(*xmin, localts, localorigin);
86}
bool track_commit_timestamp
Definition: commit_ts.c:109
bool TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts, RepOriginId *nodeid)
Definition: commit_ts.c:272
static TransactionId DatumGetTransactionId(Datum X)
Definition: postgres.h:272
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:22
static Datum slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:419

References Assert(), DatumGetTransactionId(), InvalidRepOriginId, MinTransactionIdAttributeNumber, slot_getsysattr(), track_commit_timestamp, and TransactionIdGetCommitTsData().

Referenced by apply_handle_delete_internal(), apply_handle_tuple_routing(), apply_handle_update_internal(), and CheckAndReportConflict().

◆ InitConflictIndexes()

void InitConflictIndexes ( ResultRelInfo relInfo)

Definition at line 139 of file conflict.c.

140{
141 List *uniqueIndexes = NIL;
142
143 for (int i = 0; i < relInfo->ri_NumIndices; i++)
144 {
145 Relation indexRelation = relInfo->ri_IndexRelationDescs[i];
146
147 if (indexRelation == NULL)
148 continue;
149
150 /* Detect conflict only for unique indexes */
151 if (!relInfo->ri_IndexRelationInfo[i]->ii_Unique)
152 continue;
153
154 /* Don't support conflict detection for deferrable index */
155 if (!indexRelation->rd_index->indimmediate)
156 continue;
157
158 uniqueIndexes = lappend_oid(uniqueIndexes,
159 RelationGetRelid(indexRelation));
160 }
161
162 relInfo->ri_onConflictArbiterIndexes = uniqueIndexes;
163}
int i
Definition: isn.c:77
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
#define NIL
Definition: pg_list.h:68
bool ii_Unique
Definition: execnodes.h:200
Definition: pg_list.h:54
Form_pg_index rd_index
Definition: rel.h:192
int ri_NumIndices
Definition: execnodes.h:483
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:580
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:486
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:489

References i, IndexInfo::ii_Unique, lappend_oid(), NIL, RelationData::rd_index, RelationGetRelid, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, and ResultRelInfo::ri_onConflictArbiterIndexes.

Referenced by apply_handle_insert_internal(), apply_handle_tuple_routing(), and apply_handle_update_internal().

◆ ReportApplyConflict()

void ReportApplyConflict ( EState estate,
ResultRelInfo relinfo,
int  elevel,
ConflictType  type,
TupleTableSlot searchslot,
TupleTableSlot remoteslot,
List conflicttuples 
)

Definition at line 104 of file conflict.c.

107{
108 Relation localrel = relinfo->ri_RelationDesc;
109 StringInfoData err_detail;
110
111 initStringInfo(&err_detail);
112
113 /* Form errdetail message by combining conflicting tuples information. */
114 foreach_ptr(ConflictTupleInfo, conflicttuple, conflicttuples)
115 errdetail_apply_conflict(estate, relinfo, type, searchslot,
116 conflicttuple->slot, remoteslot,
117 conflicttuple->indexoid,
118 conflicttuple->xmin,
119 conflicttuple->origin,
120 conflicttuple->ts,
121 &err_detail);
122
124
125 ereport(elevel,
127 errmsg("conflict detected on relation \"%s.%s\": conflict=%s",
129 RelationGetRelationName(localrel),
131 errdetail_internal("%s", err_detail.data));
132}
Subscription * MySubscription
Definition: worker.c:479
static void errdetail_apply_conflict(EState *estate, ResultRelInfo *relinfo, ConflictType type, TupleTableSlot *searchslot, TupleTableSlot *localslot, TupleTableSlot *remoteslot, Oid indexoid, TransactionId localxmin, RepOriginId localorigin, TimestampTz localts, StringInfo err_msg)
Definition: conflict.c:200
static const char *const ConflictTypeNames[]
Definition: conflict.c:26
static int errcode_apply_conflict(ConflictType type)
Definition: conflict.c:169
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1243
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ereport(elevel,...)
Definition: elog.h:150
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
void pgstat_report_subscription_conflict(Oid subid, ConflictType type)
#define RelationGetRelationName(relation)
Definition: rel.h:549
#define RelationGetNamespace(relation)
Definition: rel.h:556

References ConflictTypeNames, StringInfoData::data, ereport, errcode_apply_conflict(), errdetail_apply_conflict(), errdetail_internal(), errmsg(), foreach_ptr, get_namespace_name(), initStringInfo(), MySubscription, Subscription::oid, pgstat_report_subscription_conflict(), RelationGetNamespace, RelationGetRelationName, ResultRelInfo::ri_RelationDesc, and type.

Referenced by apply_handle_delete_internal(), apply_handle_tuple_routing(), apply_handle_update_internal(), and CheckAndReportConflict().

Variable Documentation

◆ ConflictTypeNames

const char* const ConflictTypeNames[]
static
Initial value:
= {
[CT_INSERT_EXISTS] = "insert_exists",
[CT_UPDATE_ORIGIN_DIFFERS] = "update_origin_differs",
[CT_UPDATE_EXISTS] = "update_exists",
[CT_UPDATE_MISSING] = "update_missing",
[CT_DELETE_ORIGIN_DIFFERS] = "delete_origin_differs",
[CT_UPDATE_DELETED] = "update_deleted",
[CT_DELETE_MISSING] = "delete_missing",
[CT_MULTIPLE_UNIQUE_CONFLICTS] = "multiple_unique_conflicts"
}

Definition at line 26 of file conflict.c.

Referenced by ReportApplyConflict().