v26-0004-Identify-if-partial-indexes-are-impacted-by-an-u.patch
application/octet-stream
Filename: v26-0004-Identify-if-partial-indexes-are-impacted-by-an-u.patch
Type: application/octet-stream
Part: 1
From 516f799c70e3d6bdf123afc9ab7650bb0edc4de6 Mon Sep 17 00:00:00 2001
From: Greg Burd <greg@burd.me>
Date: Fri, 5 Dec 2025 13:42:13 -0500
Subject: [PATCH v26 4/4] Identify if partial indexes are impacted by an
update.
The executor now determines which, if any, attributes that are indexed
are both modified and force new index tuples to be inserted ahead of
calling into the table AM update function. Prior to this commit the
test for partial indexes happened after table update, this changes that
to before so that in cases where the before and after tuples both lie
outside the predicate the attributes for the predicate are not included
in the "modified indexed attributes" bitmapset.
---
src/backend/executor/nodeModifyTable.c | 53 ++++++++++++++++++++++++--
1 file changed, 49 insertions(+), 4 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 52a74479502..c55d84f86f8 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -226,9 +226,11 @@ ExecCheckIndexedAttrsForChanges(ResultRelInfo *relinfo,
Bitmapset *m_attrs = NULL; /* (possibly) modified indexed attrs */
Bitmapset *p_attrs = NULL; /* (possibly) modified predicate attrs */
Bitmapset *u_attrs = NULL; /* unmodified indexed attrs */
+ Bitmapset *pre_attrs = indexInfo->ii_PredicateAttrs;
bool has_am_compare = (amroutine->amcomparedatums != NULL);
bool supports_ios = (amroutine->amcanreturn != NULL);
bool is_partial = (indexInfo->ii_Predicate != NIL);
+ TupleTableSlot *save_scantuple;
ExprContext *econtext = GetPerTupleExprContext(estate);
int num_datums = supports_ios ?
indexInfo->ii_NumIndexAttrs : indexInfo->ii_NumIndexKeyAttrs;
@@ -237,9 +239,51 @@ ExecCheckIndexedAttrsForChanges(ResultRelInfo *relinfo,
if (bms_is_subset(indexInfo->ii_IndexedAttrs, mix_attrs))
continue;
- /* Add partial index attributes */
- if (is_partial)
- p_attrs = bms_add_members(p_attrs, indexInfo->ii_PredicateAttrs);
+ /* Checking partial at this point isn't viable when we're serializable */
+ if (is_partial && IsolationIsSerializable())
+ {
+ p_attrs = bms_add_members(p_attrs, pre_attrs);
+ }
+ /* Check partial index predicate */
+ else if (is_partial)
+ {
+ ExprState *pstate;
+ bool old_qualifies,
+ new_qualifies;
+
+
+ if (!indexInfo->ii_CheckedPredicate)
+ pstate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
+ else
+ pstate = indexInfo->ii_PredicateState;
+
+ save_scantuple = econtext->ecxt_scantuple;
+
+ econtext->ecxt_scantuple = old_tts;
+ old_qualifies = ExecQual(pstate, econtext);
+
+ econtext->ecxt_scantuple = new_tts;
+ new_qualifies = ExecQual(pstate, econtext);
+
+ econtext->ecxt_scantuple = save_scantuple;
+
+ indexInfo->ii_CheckedPredicate = true;
+ indexInfo->ii_PredicateState = pstate;
+ indexInfo->ii_PredicateSatisfied = new_qualifies;
+
+ /* Both outside predicate, index doesn't need update */
+ if (!old_qualifies && !new_qualifies)
+ continue;
+
+ /* A transition means we need to update the index */
+ if (old_qualifies != new_qualifies)
+ p_attrs = bms_copy(pre_attrs);
+
+ /*
+ * When both are within the predicate we must update this index,
+ * but only if one of the index key attributes changed.
+ */
+ }
/* Compare the index datums for equality */
for (int j = 0; j < num_datums; j++)
@@ -275,11 +319,12 @@ ExecCheckIndexedAttrsForChanges(ResultRelInfo *relinfo,
*/
else if (rel_attrnum == 0)
{
- TupleTableSlot *save_scantuple = econtext->ecxt_scantuple;
Oid expr_type_oid;
Expr *expr = (Expr *) list_nth(indexInfo->ii_Expressions, nth_expr);
ExprState *state;
+ save_scantuple = econtext->ecxt_scantuple;
+
if (indexInfo->ii_ExpressionsState == NIL)
{
/* First time through, set up expression evaluation state */
--
2.51.2