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
Message: Re: Expanding HOT updates for expression and partial indexes
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