indexInfo->ii_OpclassOptions = NULL;
indexInfo->ii_Unique = true;
indexInfo->ii_ReadyForInserts = true;
+ indexInfo->ii_CheckedUnchanged = false;
+ indexInfo->ii_IndexUnchanged = false;
indexInfo->ii_Concurrent = false;
indexInfo->ii_BrokenHotChain = false;
indexInfo->ii_ParallelWorkers = 0;
index_unchanged_by_update(ResultRelInfo *resultRelInfo, EState *estate,
IndexInfo *indexInfo, Relation indexRelation)
{
- Bitmapset *updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
- Bitmapset *extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
+ Bitmapset *updatedCols;
+ Bitmapset *extraUpdatedCols;
Bitmapset *allUpdatedCols;
bool hasexpression = false;
List *idxExprs;
+ /*
+ * Check cache first
+ */
+ if (indexInfo->ii_CheckedUnchanged)
+ return indexInfo->ii_IndexUnchanged;
+ indexInfo->ii_CheckedUnchanged = true;
+
/*
* 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.
+ *
+ * Note that row-level BEFORE triggers won't affect our behavior, since
+ * they don't affect the updatedCols bitmaps generally. It doesn't seem
+ * worth the trouble of checking which attributes were changed directly.
*/
+ updatedCols = ExecGetUpdatedCols(resultRelInfo, estate);
+ extraUpdatedCols = ExecGetExtraUpdatedCols(resultRelInfo, estate);
for (int attr = 0; attr < indexInfo->ii_NumIndexKeyAttrs; attr++)
{
int keycol = indexInfo->ii_IndexAttrNumbers[attr];
extraUpdatedCols))
{
/* Changed key column -- don't hint for this index */
+ indexInfo->ii_IndexUnchanged = false;
return false;
}
}
* shows that the index as a whole is logically unchanged by UPDATE.
*/
if (!hasexpression)
+ {
+ indexInfo->ii_IndexUnchanged = true;
return true;
+ }
/*
* Need to pass only one bms to expression_tree_walker helper function.
bms_free(allUpdatedCols);
if (hasexpression)
+ {
+ indexInfo->ii_IndexUnchanged = false;
return false;
+ }
+ /*
+ * Deliberately don't consider index predicates. We should even give the
+ * hint when result rel's "updated tuple" has no corresponding index
+ * tuple, which is possible with a partial index (provided the usual
+ * conditions are met).
+ */
+ indexInfo->ii_IndexUnchanged = true;
return true;
}
* Unique is it a unique index?
* OpclassOptions opclass-specific options, or NULL if none
* ReadyForInserts is it valid for inserts?
+ * CheckedUnchanged IndexUnchanged status determined yet?
+ * IndexUnchanged aminsert hint, cached for retail inserts
* Concurrent are we doing a concurrent index build?
* BrokenHotChain did we detect any broken HOT chains?
* ParallelWorkers # of workers requested (excludes leader)
Datum *ii_OpclassOptions; /* array with one entry per column */
bool ii_Unique;
bool ii_ReadyForInserts;
+ bool ii_CheckedUnchanged;
+ bool ii_IndexUnchanged;
bool ii_Concurrent;
bool ii_BrokenHotChain;
int ii_ParallelWorkers;