From ac80ccfa486551e4bf519cf67c16a80da7259214 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 9 Oct 2026 16:35:25 +0800
Subject: [PATCH v1 1/1] using indnkeyatts not using indnatts in some loops

rd_indcollation, rd_opfamily and rd_opcintype only have entries for key columns,
so loops that read them must be bounded by indnkeyatts not indnatts. We can use
the existing convenient macro IndexRelationGetNumberOfKeyAttributes() for this.
---
 contrib/bloom/blutils.c              | 6 ++----
 src/backend/access/brin/brin.c       | 4 ++--
 src/backend/access/gin/ginutil.c     | 2 +-
 src/backend/commands/analyze.c       | 4 ++++
 src/backend/optimizer/util/plancat.c | 2 +-
 5 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
index 5111cdc6dd6..834ea271e43 100644
--- a/contrib/bloom/blutils.c
+++ b/contrib/bloom/blutils.c
@@ -166,12 +166,10 @@ blhandler(PG_FUNCTION_ARGS)
 void
 initBloomState(BloomState *state, Relation index)
 {
-	int			i;
-
-	state->nColumns = index->rd_att->natts;
+	state->nColumns = IndexRelationGetNumberOfKeyAttributes(index);
 
 	/* Initialize hash function for each attribute */
-	for (i = 0; i < index->rd_att->natts; i++)
+	for (int i = 0; i < state->nColumns; i++)
 	{
 		fmgr_info_copy(&(state->hashFn[i]),
 					   index_getprocinfo(index, i + 1, BLOOM_HASH_PROC),
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 5059da8dce7..41cb3896112 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -2103,7 +2103,7 @@ union_tuples(BrinDesc *bdesc, BrinMemTuple *a, BrinTuple *b)
 	}
 
 	/* Now we know neither range is empty. */
-	for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
+	for (keyno = 0; keyno < IndexRelationGetNumberOfKeyAttributes(bdesc->bd_index); keyno++)
 	{
 		FmgrInfo   *unionFn;
 		BrinValues *col_a = &a->bt_columns[keyno];
@@ -2233,7 +2233,7 @@ add_values_to_range(Relation idxRel, BrinDesc *bdesc, BrinMemTuple *dtup,
 	 * Make a note of whether this happens, so that we know to insert the
 	 * modified tuple later.
 	 */
-	for (keyno = 0; keyno < bdesc->bd_tupdesc->natts; keyno++)
+	for (keyno = 0; keyno < IndexRelationGetNumberOfKeyAttributes(bdesc->bd_index); keyno++)
 	{
 		Datum		result;
 		BrinValues *bval;
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index e7cba81d477..b64305f44c4 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -112,7 +112,7 @@ initGinState(GinState *state, Relation index)
 	state->oneCol = (origTupdesc->natts == 1);
 	state->origTupdesc = origTupdesc;
 
-	for (i = 0; i < origTupdesc->natts; i++)
+	for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(index); i++)
 	{
 		Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
 
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 518d7526255..2ec01399268 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1140,6 +1140,10 @@ examine_attribute(Relation onerel, int attnum, Node *index_expr)
 		 * If a collation has been specified for the index column, use that in
 		 * preference to anything else; but if not, fall back to whatever we
 		 * can get from the expression.
+		 *
+		 * Note: rd_indcollation covers only key columns.  That is OK here,
+		 * because INCLUDE columns cannot be expressions, so index_expr is
+		 * always a key column.
 		 */
 		if (OidIsValid(onerel->rd_indcollation[attnum - 1]))
 			stats->attrcollid = onerel->rd_indcollation[attnum - 1];
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index d067368cfc1..a8005017d91 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1219,7 +1219,7 @@ infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
 		inferopcinputtype = get_opclass_input_type(elem->inferopclass);
 	}
 
-	for (natt = 1; natt <= idxRel->rd_att->natts; natt++)
+	for (natt = 1; natt <= IndexRelationGetNumberOfKeyAttributes(idxRel); natt++)
 	{
 		Oid			opfamily = idxRel->rd_opfamily[natt - 1];
 		Oid			opcinputtype = idxRel->rd_opcintype[natt - 1];
-- 
2.34.1

