From 208ed2ec063b3a11ec490928f06b1ade0eb424d7 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 17 Dec 2025 10:31:06 +0000
Subject: [PATCH v1] Fix mismatched index_open/relation_close pairs

Several functions were using mismatched pairs of open/close functions:

- Opening with index_open() but closing with relation_close()
- Opening with relation_open() but closing with index_close()

The index_close() and relation_close() functions are currently identical in
implementation.

However, the open functions differ: index_open() validates that the relation is
an index, while relation_open() accepts any relation type.

Using matching pairs improves code clarity and ensures proper validation.

Same idea as in 171198ff2a5.

Please note that for hash_bitmap_info() and pgstathashindex() the open calls are
changed instead. For those we keep the IS_INDEX() checks to reject partitioned
indexes (which index_open() accepts via validate_relation_kind()). So, that also
changes the error messages in some tests.
---
 contrib/pageinspect/hashfuncs.c              |  2 +-
 contrib/pgstattuple/expected/pgstattuple.out | 10 +++++-----
 contrib/pgstattuple/pgstatindex.c            |  2 +-
 src/backend/access/brin/brin.c               |  4 ++--
 src/backend/parser/parse_utilcmd.c           |  2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)
  11.4% contrib/pageinspect/
  50.0% contrib/pgstattuple/expected/
   9.3% contrib/pgstattuple/
  21.6% src/backend/access/brin/
   7.4% src/backend/parser/

diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index 0e898889fa5..e086d0be4d1 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -415,7 +415,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("must be superuser to use raw page functions")));
 
-	indexRel = relation_open(indexRelid, AccessShareLock);
+	indexRel = index_open(indexRelid, AccessShareLock);
 
 	if (!IS_INDEX(indexRel) || !IS_HASH(indexRel))
 		ereport(ERROR,
diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out
index 9176dc98b6a..18d0b8ae327 100644
--- a/contrib/pgstattuple/expected/pgstattuple.out
+++ b/contrib/pgstattuple/expected/pgstattuple.out
@@ -172,7 +172,7 @@ ERROR:  relation "test_partitioned" is not a btree index
 select pgstatginindex('test_partitioned');
 ERROR:  relation "test_partitioned" is not a GIN index
 select pgstathashindex('test_partitioned');
-ERROR:  relation "test_partitioned" is not a hash index
+ERROR:  "test_partitioned" is not an index
 select pgstathashindex('test_partitioned_hash_index');
 ERROR:  relation "test_partitioned_hash_index" is not a hash index
 create view test_view as select 1;
@@ -191,7 +191,7 @@ ERROR:  relation "test_view" is not a btree index
 select pgstatginindex('test_view');
 ERROR:  relation "test_view" is not a GIN index
 select pgstathashindex('test_view');
-ERROR:  relation "test_view" is not a hash index
+ERROR:  "test_view" is not an index
 create foreign data wrapper dummy;
 create server dummy_server foreign data wrapper dummy;
 create foreign table test_foreign_table () server dummy_server;
@@ -210,7 +210,7 @@ ERROR:  relation "test_foreign_table" is not a btree index
 select pgstatginindex('test_foreign_table');
 ERROR:  relation "test_foreign_table" is not a GIN index
 select pgstathashindex('test_foreign_table');
-ERROR:  relation "test_foreign_table" is not a hash index
+ERROR:  "test_foreign_table" is not an index
 -- a partition of a partitioned table should work though
 create table test_partition partition of test_partitioned for values from (1) to (100);
 select pgstattuple('test_partition');
@@ -256,7 +256,7 @@ ERROR:  relation "test_partition" is not a btree index
 select pgstatginindex('test_partition');
 ERROR:  relation "test_partition" is not a GIN index
 select pgstathashindex('test_partition');
-ERROR:  relation "test_partition" is not a hash index
+ERROR:  "test_partition" is not an index
 -- an actual index of a partitioned table should work though
 create index test_partition_idx on test_partition(a);
 create index test_partition_hash_idx on test_partition using hash (a);
@@ -293,7 +293,7 @@ ERROR:  relation "test_sequence" is not a btree index
 select pgstatginindex('test_sequence');
 ERROR:  relation "test_sequence" is not a GIN index
 select pgstathashindex('test_sequence');
-ERROR:  relation "test_sequence" is not a hash index
+ERROR:  "test_sequence" is not an index
 select pgstattuple_approx('test_sequence');
 ERROR:  relation "test_sequence" is of wrong relation kind
 DETAIL:  This operation is not supported for sequences.
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 40823d54fca..0dfcb3960ae 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -597,7 +597,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	float8		free_percent;
 	uint64		total_space;
 
-	rel = relation_open(relid, AccessShareLock);
+	rel = index_open(relid, AccessShareLock);
 
 	if (!IS_INDEX(rel) || !IS_HASH(rel))
 		ereport(ERROR,
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 26cb75058d1..a4c46ef3291 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1478,7 +1478,7 @@ brin_summarize_range(PG_FUNCTION_ARGS)
 	/* Restore userid and security context */
 	SetUserIdAndSecContext(save_userid, save_sec_context);
 
-	relation_close(indexRel, ShareUpdateExclusiveLock);
+	index_close(indexRel, ShareUpdateExclusiveLock);
 	relation_close(heapRel, ShareUpdateExclusiveLock);
 
 	PG_RETURN_INT32((int32) numSummarized);
@@ -1568,7 +1568,7 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
 				 errmsg("index \"%s\" is not valid",
 						RelationGetRelationName(indexRel))));
 
-	relation_close(indexRel, ShareUpdateExclusiveLock);
+	index_close(indexRel, ShareUpdateExclusiveLock);
 	relation_close(heapRel, ShareUpdateExclusiveLock);
 
 	PG_RETURN_VOID();
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 375b40b29af..2b7b084f216 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2572,7 +2572,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 		}
 
 		/* Close the index relation but keep the lock */
-		relation_close(index_rel, NoLock);
+		index_close(index_rel, NoLock);
 
 		index->indexOid = index_oid;
 	}
-- 
2.34.1

