From 9423421a695b4d560cf7bfc7e6f2dcd1c630084d Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Fri, 31 Oct 2025 14:55:25 -0400 Subject: [PATCH v27 3/4] Replace index_unchanged_by_update() with ri_ChangedIndexedCols In execIndexing on updates we'd like to pass a hint to the indexing code when the indexed attributes are unchanged. This commit replaces the now redundant code in index_unchanged_by_update() with the same information found earlier in ExecWhichIndexesRequireUpdates() and stashed in ri_ChangedIndexedCols. --- src/backend/catalog/toasting.c | 2 - src/backend/executor/execIndexing.c | 156 +--------------------------- src/backend/nodes/makefuncs.c | 2 - src/include/nodes/execnodes.h | 4 - 4 files changed, 1 insertion(+), 163 deletions(-) diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index ff8da5be5f8..5675c6f8ea9 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -304,8 +304,6 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, indexInfo->ii_Unique = true; indexInfo->ii_NullsNotDistinct = false; indexInfo->ii_ReadyForInserts = true; - indexInfo->ii_CheckedUnchanged = false; - indexInfo->ii_IndexUnchanged = false; indexInfo->ii_Concurrent = false; indexInfo->ii_BrokenHotChain = false; indexInfo->ii_ParallelWorkers = 0; diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 1275feffae9..b75e76401d2 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -143,11 +143,6 @@ static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, static bool index_recheck_constraint(Relation index, const Oid *constr_procs, const Datum *existing_values, const bool *existing_isnull, const 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); static void ExecWithoutOverlapsNotEmpty(Relation rel, NameData attname, Datum attval, char typtype, Oid atttypid); @@ -451,10 +446,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, * 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); + indexUnchanged = update && bms_is_empty(resultRelInfo->ri_ChangedIndexedCols); satisfiesConstraint = index_insert(indexRelation, /* index relation */ @@ -1014,152 +1006,6 @@ index_recheck_constraint(Relation index, const 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; - 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]; - - 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 */ - indexInfo->ii_IndexUnchanged = false; - 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) - { - indexInfo->ii_IndexUnchanged = true; - 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) - { - 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; -} - -/* - * 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, - allUpdatedCols); -} - /* * ExecWithoutOverlapsNotEmpty - raise an error if the tuple has an empty * range or multirange in the given attribute. diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index dd092bacad9..9d3a5b79d27 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -845,8 +845,6 @@ makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, n->ii_Unique = unique; n->ii_NullsNotDistinct = nulls_not_distinct; n->ii_ReadyForInserts = isready; - n->ii_CheckedUnchanged = false; - n->ii_IndexUnchanged = false; n->ii_Concurrent = concurrent; n->ii_Summarizing = summarizing; n->ii_WithoutOverlaps = withoutoverlaps; diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d5af2f34d0f..8e583b1d9d3 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -216,10 +216,6 @@ typedef struct IndexInfo bool ii_NullsNotDistinct; /* is it valid for inserts? */ bool ii_ReadyForInserts; - /* IndexUnchanged status determined yet? */ - bool ii_CheckedUnchanged; - /* aminsert hint, cached for retail inserts */ - bool ii_IndexUnchanged; /* are we doing a concurrent index build? */ bool ii_Concurrent; /* did we detect any broken HOT chains? */ -- 2.51.2