index 32b5d62e1f34cf9bdc46a142beee52fa83182b46..d37ceef753ab0110e38cade086699e62e3e2fdff 100644 (file)
blinsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
BloomState blstate;
index 436bd43209245c49e4349824217b82883cb0667f..a22a6dfa404006a98dbc4c950fdd607be23b6e30 100644 (file)
extern bool blinsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern IndexScanDesc blbeginscan(Relation r, int nkeys, int norderbys);
extern int64 blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
index f00268d5b51f2c6818d333ada386cd47068a7240..ec5741df6d16414691565a93a959978e4b14b04b 100644 (file)
ItemPointer heap_tid,
Relation heapRelation,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo);
</programlisting>
Insert a new tuple into an existing index. The <literal>values</literal> and
look into the heap to verify tuple liveness).
</para>
+ <para>
+ The <literal>indexUnchanged</literal> boolean value gives a hint
+ about the nature of the tuple to be indexed. When it is true,
+ the tuple is a duplicate of some existing tuple in the index. The
+ new tuple is a logically unchanged successor MVCC tuple version. This
+ happens when an <command>UPDATE</command> takes place that does not
+ modify any columns covered by the index, but nevertheless requires a
+ new version in the index. The index AM may use this hint to decide
+ to apply bottom-up index deletion in parts of the index where many
+ versions of the same logical row accumulate. Note that updating a
+ non-key column does not affect the value of
+ <literal>indexUnchanged</literal>.
+ </para>
+
<para>
The function's Boolean result value is significant only when
<literal>checkUnique</literal> is <literal>UNIQUE_CHECK_PARTIAL</literal>.
index 58fe109d2d9c5d0d2dbab5fde55d8459b3cb91a4..27ba596c6e47deb0701ad151e4b4be539cd32419 100644 (file)
brininsert(Relation idxRel, Datum *values, bool *nulls,
ItemPointer heaptid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
BlockNumber pagesPerRange;
index 70a9f771884fb3f5ce8e82be1b41e3d75e2ae1ce..9b9da0f41bcd7bf18b9a226efa80b23b6fc4b0fe 100644 (file)
@@ -328,7 +328,7 @@ toast_save_datum(Relation rel, Datum value,
toastrel,
toastidxs[i]->rd_index->indisunique ?
UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
- NULL);
+ false, NULL);
}
/*
index 29546ce0ae48df992813d566fe4ddcc1472b1905..0e8672c9e90ccead7cf5a3bf0816bedc9ac9bd1b 100644 (file)
gininsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
index e4b251a58fb573a2e49cb980cde7b18fccf3655b..992936cfa8eaca51f4854b8cbe8fe7b04724fffc 100644 (file)
gistinsert(Relation r, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
index 263ae23ab0ad9298f3f4ea8042f607bf3ba270d9..0752fb38a9248d76f6f02844e5fbe463f7af7f08 100644 (file)
hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
Datum index_values[1];
index 10ddde4ecf949330d8a79329775e96884526bec0..ac4a3be458739601734b72b56643dbc1e01c9f7c 100644 (file)
@@ -1956,6 +1956,7 @@ heapam_index_validate_scan(Relation heapRelation,
heapRelation,
indexInfo->ii_Unique ?
UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ false,
indexInfo);
state->tups_inserted += 1;
index c2b98e8a727d1294f349f3dda35615c8be32d176..3d2dbed70830979e0eb4222852127799694dc57b 100644 (file)
ItemPointer heap_t_ctid,
Relation heapRelation,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
RELATION_CHECKS;
return indexRelation->rd_indam->aminsert(indexRelation, values, isnull,
heap_t_ctid, heapRelation,
- checkUnique, indexInfo);
+ checkUnique, indexUnchanged,
+ indexInfo);
}
/*
index ba79a7f3e9e2c4e59089a7e5e1d9569fb6de9c39..c50c4e8434ba609596b1fcccc1ad815b38d3d4dd 100644 (file)
btinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
bool result;
index 2e1d8a33d1f7d07b2dc697326e24baaa067dcbfe..0ca621450e647e01d157785f87941e85392e3622 100644 (file)
spginsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
SpGistState spgstate;
index 8701653eb6162e3f185564148100eef61b82ec0f..284ceaa6b9c00852a0aa806306d50977466e49a0 100644 (file)
@@ -162,6 +162,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple)
heapRelation,
index->rd_index->indisunique ?
UNIQUE_CHECK_YES : UNIQUE_CHECK_NO,
+ false,
indexInfo);
}
index c2394d2232e6de73ff1ccc2fe31c984cf2ec56fa..d0063164a7e4e706cd958463974c3a8405e7500d 100644 (file)
*/
index_insert(indexRel, values, isnull, &checktid,
trigdata->tg_relation, UNIQUE_CHECK_EXISTING,
- indexInfo);
+ false, indexInfo);
}
else
{
index 08b6f782c735879f4f93e3c0a2945316eb7eab55..c39cc736ed2bc700a6fed05f12b62bd4dda44984 100644 (file)
@@ -342,8 +342,8 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
cstate->cur_lineno = buffer->linenos[i];
recheckIndexes =
ExecInsertIndexTuples(resultRelInfo,
- buffer->slots[i], estate, false, NULL,
- NIL);
+ buffer->slots[i], estate, false, false,
+ NULL, NIL);
ExecARInsertTriggers(estate, resultRelInfo,
slots[i], recheckIndexes,
cstate->transition_capture);
myslot,
estate,
false,
+ false,
NULL,
NIL);
}
index 12229364f1e92e943ad3771eeb7608c2d1b2e2c4..3e7086c5e52957f7223830dbd48112a7939e79a6 100644 (file)
@@ -71,10 +71,8 @@ int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
static int MyTriggerDepth = 0;
/*
- * Note that similar macros also exist in executor/execMain.c. There does not
- * appear to be any good header to put them into, given the structures that
- * they use, so we let them be duplicated. Be sure to update all if one needs
- * to be changed, however.
+ * The authoritative version of this macro is in executor/execMain.c. Be sure
+ * to keep everything in sync.
*/
#define GetAllUpdatedColumns(relinfo, estate) \
(bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \
index 2aafcc8f2298bbf77abe54ede5f1835fca1cb24f..1f0fe145ce8eb9d95c7e75b9671d6c32243a7230 100644 (file)
CEOUC_LIVELOCK_PREVENTING_WAIT
} CEOUC_WAIT_MODE;
+/*
+ * The authoritative version of these macro are in executor/execMain.c. Be
+ * sure to keep everything in sync.
+ */
+#define GetUpdatedColumns(relinfo, estate) \
+ (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols)
+#define GetExtraUpdatedColumns(relinfo, estate) \
+ (exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols)
+
static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
IndexInfo *indexInfo,
ItemPointer tupleid,
@@ -136,6 +145,11 @@ static bool check_exclusion_or_unique_constraint(Relation heap, Relation index,
static bool index_recheck_constraint(Relation index, Oid *constr_procs,
Datum *existing_values, bool *existing_isnull,
Datum *new_values);
+static bool index_unchanged_by_update(ResultRelInfo *resultRelInfo,
+ EState *estate, IndexInfo *indexInfo,
+ Relation indexRelation);
+static bool index_expression_changed_walker(Node *node,
+ Bitmapset *allUpdatedCols);
/* ----------------------------------------------------------------
* ExecOpenIndices
@@ -254,6 +268,16 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
* into all the relations indexing the result relation
* when a heap tuple is inserted into the result relation.
*
+ * When 'update' is true, executor is performing an UPDATE
+ * that could not use an optimization like heapam's HOT (in
+ * more general terms a call to table_tuple_update() took
+ * place and set 'update_indexes' to true). Receiving this
+ * hint makes us consider if we should pass down the
+ * 'indexUnchanged' hint in turn. That's something that we
+ * figure out for each index_insert() call iff 'update' is
+ * true. (When 'update' is false we already know not to pass
+ * the hint to any index.)
+ *
* Unique and exclusion constraints are enforced at the same
* time. This returns a list of index OIDs for any unique or
* exclusion constraints that are deferred and that had
*
* If 'arbiterIndexes' is nonempty, noDupErr applies only to
* those indexes. NIL means noDupErr applies to all indexes.
- *
- * CAUTION: this must not be called for a HOT update.
- * We can't defend against that here for lack of info.
- * Should we change the API to make it safer?
* ----------------------------------------------------------------
*/
List *
ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot,
EState *estate,
+ bool update,
bool noDupErr,
bool *specConflict,
List *arbiterIndexes)
@@ -319,6 +340,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
IndexInfo *indexInfo;
bool applyNoDupErr;
IndexUniqueCheck checkUnique;
+ bool indexUnchanged;
bool satisfiesConstraint;
if (indexRelation == NULL)
@@ -389,6 +411,16 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
else
checkUnique = UNIQUE_CHECK_PARTIAL;
+ /*
+ * There's definitely going to be an index_insert() call for this
+ * index. If we're being called as part of an UPDATE statement,
+ * consider if the 'indexUnchanged' = true hint should be passed.
+ */
+ indexUnchanged = update && index_unchanged_by_update(resultRelInfo,
+ estate,
+ indexInfo,
+ indexRelation);
+
satisfiesConstraint =
index_insert(indexRelation, /* index relation */
values, /* array of index Datums */
@@ -396,6 +428,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
tupleid, /* tid of heap tuple */
heapRelation, /* heap relation */
checkUnique, /* type of uniqueness check to do */
+ indexUnchanged, /* UPDATE without logical change? */
indexInfo); /* index AM may need this */
/*
@@ -899,3 +932,122 @@ index_recheck_constraint(Relation index, Oid *constr_procs,
return true;
}
+
+/*
+ * Check if ExecInsertIndexTuples() should pass indexUnchanged hint.
+ *
+ * When the executor performs an UPDATE that requires a new round of index
+ * tuples, determine if we should pass 'indexUnchanged' = true hint for one
+ * single index.
+ */
+static bool
+index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
+ IndexInfo *indexInfo, Relation indexRelation)
+{
+ Bitmapset *updatedCols = GetUpdatedColumns(resultRelInfo, estate);
+ Bitmapset *extraUpdatedCols = GetExtraUpdatedColumns(resultRelInfo, estate);
+ Bitmapset *allUpdatedCols;
+ bool hasexpression = false;
+ List *idxExprs;
+
+ /*
+ * Check for indexed attribute overlap with updated columns.
+ *
+ * Only do this for key columns. A change to a non-key column within an
+ * INCLUDE index should not be counted here. Non-key column values are
+ * opaque payload state to the index AM, a little like an extra table TID.
+ */
+ for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
+ {
+ int keycol = indexInfo->ii_IndexAttrNumbers[attr];
+
+ if (keycol <= 0)
+ {
+ /*
+ * Skip expressions for now, but remember to deal with them later
+ * on
+ */
+ hasexpression = true;
+ continue;
+ }
+
+ if (bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
+ updatedCols) ||
+ bms_is_member(keycol - FirstLowInvalidHeapAttributeNumber,
+ extraUpdatedCols))
+ {
+ /* Changed key column -- don't hint for this index */
+ return false;
+ }
+ }
+
+ /*
+ * When we get this far and index has no expressions, return true so that
+ * index_insert() call will go on to pass 'indexUnchanged' = true hint.
+ *
+ * The _absence_ of an indexed key attribute that overlaps with updated
+ * attributes (in addition to the total absence of indexed expressions)
+ * shows that the index as a whole is logically unchanged by UPDATE.
+ */
+ if (!hasexpression)
+ return true;
+
+ /*
+ * Need to pass only one bms to expression_tree_walker helper function.
+ * Avoid allocating memory in common case where there are no extra cols.
+ */
+ if (!extraUpdatedCols)
+ allUpdatedCols = updatedCols;
+ else
+ allUpdatedCols = bms_union(updatedCols, extraUpdatedCols);
+
+ /*
+ * We have to work slightly harder in the event of indexed expressions,
+ * but the principle is the same as before: try to find columns (Vars,
+ * actually) that overlap with known-updated columns.
+ *
+ * If we find any matching Vars, don't pass hint for index. Otherwise
+ * pass hint.
+ */
+ idxExprs = RelationGetIndexExpressions(indexRelation);
+ hasexpression = index_expression_changed_walker((Node *) idxExprs,
+ allUpdatedCols);
+ list_free(idxExprs);
+ if (extraUpdatedCols)
+ bms_free(allUpdatedCols);
+
+ if (hasexpression)
+ return false;
+
+ return true;
+}
+
+/*
+ * Indexed expression helper for index_unchanged_by_update().
+ *
+ * Returns true when Var that appears within allUpdatedCols located.
+ */
+static bool
+index_expression_changed_walker(Node *node, Bitmapset *allUpdatedCols)
+{
+ if (node == NULL)
+ return false;
+
+ if (IsA(node, Var))
+ {
+ Var *var = (Var *) node;
+
+ if (bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
+ allUpdatedCols))
+ {
+ /* Var was updated -- indicates that we should not hint */
+ return true;
+ }
+
+ /* Still haven't found a reason to not pass the hint */
+ return false;
+ }
+
+ return expression_tree_walker(node, index_expression_changed_walker,
+ (void *) allUpdatedCols);
+}
index b4e25df601bd2235f92f76bf2d1c5b52263d2846..f4dd47acc76ac54f74ebb7ec0526ab68592b68f1 100644 (file)
@@ -101,10 +101,10 @@ static char *ExecBuildSlotValueDescription(Oid reloid,
static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree);
/*
- * Note that GetAllUpdatedColumns() also exists in commands/trigger.c. There does
- * not appear to be any good header to put it into, given the structures that
- * it uses, so we let them be duplicated. Be sure to update both if one needs
- * to be changed, however.
+ * Note that variants of these macros exists in commands/trigger.c and in
+ * execIndexing.c. There does not appear to be any good header to put it
+ * into, given the structures that it uses, so we let them be duplicated. Be
+ * sure to keep everything in sync.
*/
#define GetInsertedColumns(relinfo, estate) \
(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->insertedCols)
index 12f6e5c6778fa71f357c4bf40c1efca84c0cfccd..1e285e0349f46dea9387ed750879d7ecaff220f1 100644 (file)
@@ -444,8 +444,8 @@ ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo,
if (resultRelInfo->ri_NumIndices > 0)
recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
- slot, estate, false, NULL,
- NIL);
+ slot, estate, false, false,
+ NULL, NIL);
/* AFTER ROW INSERT Triggers */
ExecARInsertTriggers(estate, resultRelInfo, slot,
@@ -512,8 +512,8 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo,
if (resultRelInfo->ri_NumIndices > 0 && update_indexes)
recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
- slot, estate, false, NULL,
- NIL);
+ slot, estate, true, false,
+ NULL, NIL);
/* AFTER ROW UPDATE Triggers */
ExecARUpdateTriggers(estate, resultRelInfo,
index d7b8f6559196fdf642e9bd605f1846d4bb5e1c78..921e6954194ea635d130f536d3c3980a0615aa47 100644 (file)
/* insert index entries for tuple */
recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
- slot, estate, true,
+ slot, estate, false, true,
&specConflict,
arbiterIndexes);
if (resultRelInfo->ri_NumIndices > 0)
recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
slot, estate, false,
- NULL, NIL);
+ false, NULL, NIL);
}
}
/* insert index entries for tuple if necessary */
if (resultRelInfo->ri_NumIndices > 0 && update_indexes)
recheckIndexes = ExecInsertIndexTuples(resultRelInfo,
- slot, estate, false,
+ slot, estate, true, false,
NULL, NIL);
}
index 1b1d70ed68aa53c677a3f1091b0f91156636e14f..f2b2549a51584c4a90686b610b1d499eec4c45ee 100644 (file)
InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0);
/*
- * Populate updatedCols so that per-column triggers can fire. This could
+ * Populate updatedCols so that per-column triggers can fire, and so
+ * executor can correctly pass down indexUnchanged hint. This could
* include more columns than were actually changed on the publisher
* because the logical replication protocol doesn't contain that
* information. But it would for example exclude columns that only exist
index de758cab0bde40a8e549be728909282e629acd7f..d357ebb559804b174bfb769041ec3630c4382f68 100644 (file)
@@ -110,6 +110,7 @@ typedef bool (*aminsert_function) (Relation indexRelation,
ItemPointer heap_tid,
Relation heapRelation,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
/* bulk delete */
index 85c612e4902c5728be3d166154798973329754be..78c89a69617366b7d7f637b806eb9af6d06ff16b 100644 (file)
@@ -91,6 +91,7 @@ extern void brinbuildempty(Relation index);
extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
ItemPointer heaptid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
index aa8ff360daac41e1828fc6ac0e6dd42a4710a347..0eab1508d37538eb940a0926de6f2a7a54bef874 100644 (file)
@@ -143,6 +143,7 @@ extern bool index_insert(Relation indexRelation,
ItemPointer heap_t_ctid,
Relation heapRelation,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern IndexScanDesc index_beginscan(Relation heapRelation,
index a7a71ae1b4c49a98a682a80dd6876e5467b3ae1e..670a40b4bee8dc430f196175dc15f9fd65c89319 100644 (file)
@@ -116,6 +116,7 @@ extern void ginbuildempty(Relation index);
extern bool gininsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern void ginEntryInsert(GinState *ginstate,
OffsetNumber attnum, Datum key, GinNullCategory category,
index e899e817496b4853c2e1a3000ad5421a326cbef7..553d364e2d1e355bd071d446c77bd16dc7442c98 100644 (file)
@@ -403,6 +403,7 @@ extern void gistbuildempty(Relation index);
extern bool gistinsert(Relation r, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern MemoryContext createTempGistContext(void);
extern GISTSTATE *initGISTstate(Relation index);
index 22a99e70837da026020b938fcc99b6b107ab3a06..1cce865be2b04241a2b7a89a922952fed64572bc 100644 (file)
@@ -364,6 +364,7 @@ extern void hashbuildempty(Relation index);
extern bool hashinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir);
extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
index b793dab9fa66cdf5c2d2c1498dafe6992ad65267..7f8489aac2a00962593ab358b08a1b60f255f12a 100644 (file)
@@ -996,6 +996,7 @@ extern void btbuildempty(Relation index);
extern bool btinsert(Relation rel, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys);
extern Size btestimateparallelscan(void);
index 38a5902202bfe4e5826297c21a370fab1531d3a7..2eb2f421a8714936479d9360824b90f4058476da 100644 (file)
@@ -199,6 +199,7 @@ extern void spgbuildempty(Relation index);
extern bool spginsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
struct IndexInfo *indexInfo);
/* spgscan.c */
index 53f431e1ed79ffa9986bea2308666ad2e8d96ba1..758c3ca0974a0031fc604e098197157363c3ac89 100644 (file)
@@ -581,6 +581,7 @@ extern void ExecOpenIndices(ResultRelInfo *resultRelInfo, bool speculative);
extern void ExecCloseIndices(ResultRelInfo *resultRelInfo);
extern List *ExecInsertIndexTuples(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate,
+ bool update,
bool noDupErr,
bool *specConflict, List *arbiterIndexes);
extern bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo,
index ac35023fb5c0e095b9d32c01a7dec6347ee5b6ea..5365b0639ec3369a286d7a447050fe855039fbd8 100644 (file)
diinsert(Relation index, Datum *values, bool *isnull,
ItemPointer ht_ctid, Relation heapRel,
IndexUniqueCheck checkUnique,
+ bool indexUnchanged,
IndexInfo *indexInfo)
{
/* nothing to do */