PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 461 of file conflict.c.

463{
464 char *index_value;
465 Relation indexDesc;
467 bool isnull[INDEX_MAX_KEYS];
468 TupleTableSlot *tableslot = slot;
469
470 if (!tableslot)
471 return NULL;
472
474
475 indexDesc = index_open(indexoid, NoLock);
476
477 /*
478 * If the slot is a virtual slot, copy it into a heap tuple slot as
479 * FormIndexDatum only works with heap tuple slots.
480 */
481 if (TTS_IS_VIRTUAL(slot))
482 {
483 tableslot = table_slot_create(localrel, &estate->es_tupleTable);
484 tableslot = ExecCopySlot(tableslot, slot);
485 }
486
487 /*
488 * Initialize ecxt_scantuple for potential use in FormIndexDatum when
489 * index expressions are present.
490 */
491 GetPerTupleExprContext(estate)->ecxt_scantuple = tableslot;
492
493 /*
494 * The values/nulls arrays passed to BuildIndexValueDescription should be
495 * the results of FormIndexDatum, which are the "raw" input to the index
496 * AM.
497 */
498 FormIndexDatum(BuildIndexInfo(indexDesc), tableslot, estate, values, isnull);
499
500 index_value = BuildIndexValueDescription(indexDesc, values, isnull);
501
502 index_close(indexDesc, NoLock);
503
504 return index_value;
505}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define GetPerTupleExprContext(estate)
Definition: executor.h:678
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
uintptr_t Datum
Definition: postgres.h:69
List * es_tupleTable
Definition: execnodes.h:710
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92
#define TTS_IS_VIRTUAL(slot)
Definition: tuptable.h:238
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:525

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 318 of file conflict.c.

324{
325 Relation localrel = relinfo->ri_RelationDesc;
326 Oid relid = RelationGetRelid(localrel);
327 TupleDesc tupdesc = RelationGetDescr(localrel);
328 StringInfoData tuple_value;
329 char *desc = NULL;
330
331 Assert(searchslot || localslot || remoteslot);
332
333 initStringInfo(&tuple_value);
334
335 /*
336 * Report the conflicting key values in the case of a unique constraint
337 * violation.
338 */
341 {
342 Assert(OidIsValid(indexoid) && localslot);
343
344 desc = build_index_value_desc(estate, localrel, localslot, indexoid);
345
346 if (desc)
347 appendStringInfo(&tuple_value, _("Key %s"), desc);
348 }
349
350 if (localslot)
351 {
352 /*
353 * The 'modifiedCols' only applies to the new tuple, hence we pass
354 * NULL for the existing local tuple.
355 */
356 desc = ExecBuildSlotValueDescription(relid, localslot, tupdesc,
357 NULL, 64);
358
359 if (desc)
360 {
361 if (tuple_value.len > 0)
362 {
363 appendStringInfoString(&tuple_value, "; ");
364 appendStringInfo(&tuple_value, _("existing local tuple %s"),
365 desc);
366 }
367 else
368 {
369 appendStringInfo(&tuple_value, _("Existing local tuple %s"),
370 desc);
371 }
372 }
373 }
374
375 if (remoteslot)
376 {
377 Bitmapset *modifiedCols;
378
379 /*
380 * Although logical replication doesn't maintain the bitmap for the
381 * columns being inserted, we still use it to create 'modifiedCols'
382 * for consistency with other calls to ExecBuildSlotValueDescription.
383 *
384 * Note that generated columns are formed locally on the subscriber.
385 */
386 modifiedCols = bms_union(ExecGetInsertedCols(relinfo, estate),
387 ExecGetUpdatedCols(relinfo, estate));
388 desc = ExecBuildSlotValueDescription(relid, remoteslot, tupdesc,
389 modifiedCols, 64);
390
391 if (desc)
392 {
393 if (tuple_value.len > 0)
394 {
395 appendStringInfoString(&tuple_value, "; ");
396 appendStringInfo(&tuple_value, _("remote tuple %s"), desc);
397 }
398 else
399 {
400 appendStringInfo(&tuple_value, _("Remote tuple %s"), desc);
401 }
402 }
403 }
404
405 if (searchslot)
406 {
407 /*
408 * Note that while index other than replica identity may be used (see
409 * IsIndexUsableForReplicaIdentityFull for details) to find the tuple
410 * when applying update or delete, such an index scan may not result
411 * in a unique tuple and we still compare the complete tuple in such
412 * cases, thus such indexes are not used here.
413 */
414 Oid replica_index = GetRelationIdentityOrPK(localrel);
415
417
418 /*
419 * If the table has a valid replica identity index, build the index
420 * key value string. Otherwise, construct the full tuple value for
421 * REPLICA IDENTITY FULL cases.
422 */
423 if (OidIsValid(replica_index))
424 desc = build_index_value_desc(estate, localrel, searchslot, replica_index);
425 else
426 desc = ExecBuildSlotValueDescription(relid, searchslot, tupdesc, NULL, 64);
427
428 if (desc)
429 {
430 if (tuple_value.len > 0)
431 {
432 appendStringInfoString(&tuple_value, "; ");
433 appendStringInfo(&tuple_value, OidIsValid(replica_index)
434 ? _("replica identity %s")
435 : _("replica identity full %s"), desc);
436 }
437 else
438 {
439 appendStringInfo(&tuple_value, OidIsValid(replica_index)
440 ? _("Replica identity %s")
441 : _("Replica identity full %s"), desc);
442 }
443 }
444 }
445
446 if (tuple_value.len == 0)
447 return NULL;
448
449 appendStringInfoChar(&tuple_value, '.');
450 return tuple_value.data;
451}
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
#define OidIsValid(objectId)
Definition: c.h:746
static char * build_index_value_desc(EState *estate, Relation localrel, TupleTableSlot *slot, Oid indexoid)
Definition: conflict.c:461
@ CT_MULTIPLE_UNIQUE_CONFLICTS
Definition: conflict.h:45
@ CT_INSERT_EXISTS
Definition: conflict.h:27
@ CT_UPDATE_EXISTS
Definition: conflict.h:33
#define _(x)
Definition: elog.c:91
char * ExecBuildSlotValueDescription(Oid reloid, TupleTableSlot *slot, TupleDesc tupdesc, Bitmapset *modifiedCols, int maxfieldlen)
Definition: execMain.c:2467
Bitmapset * ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1362
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1383
unsigned int Oid
Definition: postgres_ext.h:30
#define RelationGetRelid(relation)
Definition: rel.h:516
#define RelationGetDescr(relation)
Definition: rel.h:542
Oid GetRelationIdentityOrPK(Relation rel)
Definition: relation.c:891
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:475
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 168 of file conflict.c.

169{
170 switch (type)
171 {
172 case CT_INSERT_EXISTS:
173 case CT_UPDATE_EXISTS:
175 return errcode(ERRCODE_UNIQUE_VIOLATION);
181 }
182
183 Assert(false);
184 return 0; /* silence compiler warning */
185}
@ CT_DELETE_MISSING
Definition: conflict.h:42
@ CT_UPDATE_ORIGIN_DIFFERS
Definition: conflict.h:30
@ CT_UPDATE_MISSING
Definition: conflict.h:36
@ CT_DELETE_ORIGIN_DIFFERS
Definition: conflict.h:39
int errcode(int sqlerrcode)
Definition: elog.c:854
#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_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 198 of file conflict.c.

204{
205 StringInfoData err_detail;
206 char *val_desc;
207 char *origin_name;
208
209 initStringInfo(&err_detail);
210
211 /* First, construct a detailed message describing the type of conflict */
212 switch (type)
213 {
214 case CT_INSERT_EXISTS:
215 case CT_UPDATE_EXISTS:
217 Assert(OidIsValid(indexoid) &&
219
220 if (localts)
221 {
222 if (localorigin == InvalidRepOriginId)
223 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified locally in transaction %u at %s."),
224 get_rel_name(indexoid),
225 localxmin, timestamptz_to_str(localts));
226 else if (replorigin_by_oid(localorigin, true, &origin_name))
227 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified by origin \"%s\" in transaction %u at %s."),
228 get_rel_name(indexoid), origin_name,
229 localxmin, timestamptz_to_str(localts));
230
231 /*
232 * The origin that modified this row has been removed. This
233 * can happen if the origin was created by a different apply
234 * worker and its associated subscription and origin were
235 * dropped after updating the row, or if the origin was
236 * manually dropped by the user.
237 */
238 else
239 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified by a non-existent origin in transaction %u at %s."),
240 get_rel_name(indexoid),
241 localxmin, timestamptz_to_str(localts));
242 }
243 else
244 appendStringInfo(&err_detail, _("Key already exists in unique index \"%s\", modified in transaction %u."),
245 get_rel_name(indexoid), localxmin);
246
247 break;
248
250 if (localorigin == InvalidRepOriginId)
251 appendStringInfo(&err_detail, _("Updating the row that was modified locally in transaction %u at %s."),
252 localxmin, timestamptz_to_str(localts));
253 else if (replorigin_by_oid(localorigin, true, &origin_name))
254 appendStringInfo(&err_detail, _("Updating the row that was modified by a different origin \"%s\" in transaction %u at %s."),
255 origin_name, localxmin, timestamptz_to_str(localts));
256
257 /* The origin that modified this row has been removed. */
258 else
259 appendStringInfo(&err_detail, _("Updating the row that was modified by a non-existent origin in transaction %u at %s."),
260 localxmin, timestamptz_to_str(localts));
261
262 break;
263
265 appendStringInfoString(&err_detail, _("Could not find the row to be updated."));
266 break;
267
269 if (localorigin == InvalidRepOriginId)
270 appendStringInfo(&err_detail, _("Deleting the row that was modified 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, _("Deleting the row that was modified 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, _("Deleting the row that was modified by a non-existent origin in transaction %u at %s."),
279 localxmin, timestamptz_to_str(localts));
280
281 break;
282
284 appendStringInfoString(&err_detail, _("Could not find the row to be deleted."));
285 break;
286 }
287
288 Assert(err_detail.len > 0);
289
290 val_desc = build_tuple_value_details(estate, relinfo, type, searchslot,
291 localslot, remoteslot, indexoid);
292
293 /*
294 * Next, append the key values, existing local tuple, remote tuple and
295 * replica identity columns after the message.
296 */
297 if (val_desc)
298 appendStringInfo(&err_detail, "\n%s", val_desc);
299
300 /*
301 * Insert a blank line to visually separate the new detail line from the
302 * existing ones.
303 */
304 if (err_msg->len > 0)
305 appendStringInfoChar(err_msg, '\n');
306
307 appendStringInfoString(err_msg, err_detail.data);
308}
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:318
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2068
bool replorigin_by_oid(RepOriginId roident, bool missing_ok, char **roname)
Definition: origin.c:470
#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_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 62 of file conflict.c.

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

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 138 of file conflict.c.

139{
140 List *uniqueIndexes = NIL;
141
142 for (int i = 0; i < relInfo->ri_NumIndices; i++)
143 {
144 Relation indexRelation = relInfo->ri_IndexRelationDescs[i];
145
146 if (indexRelation == NULL)
147 continue;
148
149 /* Detect conflict only for unique indexes */
150 if (!relInfo->ri_IndexRelationInfo[i]->ii_Unique)
151 continue;
152
153 /* Don't support conflict detection for deferrable index */
154 if (!indexRelation->rd_index->indimmediate)
155 continue;
156
157 uniqueIndexes = lappend_oid(uniqueIndexes,
158 RelationGetRelid(indexRelation));
159 }
160
161 relInfo->ri_onConflictArbiterIndexes = uniqueIndexes;
162}
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:209
Definition: pg_list.h:54
Form_pg_index rd_index
Definition: rel.h:192
int ri_NumIndices
Definition: execnodes.h:478
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:575
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:481
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:484

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 103 of file conflict.c.

106{
107 Relation localrel = relinfo->ri_RelationDesc;
108 StringInfoData err_detail;
109
110 initStringInfo(&err_detail);
111
112 /* Form errdetail message by combining conflicting tuples information. */
113 foreach_ptr(ConflictTupleInfo, conflicttuple, conflicttuples)
114 errdetail_apply_conflict(estate, relinfo, type, searchslot,
115 conflicttuple->slot, remoteslot,
116 conflicttuple->indexoid,
117 conflicttuple->xmin,
118 conflicttuple->origin,
119 conflicttuple->ts,
120 &err_detail);
121
123
124 ereport(elevel,
126 errmsg("conflict detected on relation \"%s.%s\": conflict=%s",
128 RelationGetRelationName(localrel),
130 errdetail_internal("%s", err_detail.data));
131}
Subscription * MySubscription
Definition: worker.c:299
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:198
static const char *const ConflictTypeNames[]
Definition: conflict.c:26
static int errcode_apply_conflict(ConflictType type)
Definition: conflict.c:168
int errdetail_internal(const char *fmt,...)
Definition: elog.c:1231
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereport(elevel,...)
Definition: elog.h:149
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3506
#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:550
#define RelationGetNamespace(relation)
Definition: rel.h:557

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_DELETE_MISSING] = "delete_missing",
[CT_MULTIPLE_UNIQUE_CONFLICTS] = "multiple_unique_conflicts"
}

Definition at line 26 of file conflict.c.

Referenced by ReportApplyConflict().