From bd48ef6db6c83739ff5949d0945982ec9e6a90b8 Mon Sep 17 00:00:00 2001
From: Mikhail Nikalayeu <mihailnikalayeu@gmail.com>
Date: Sun, 25 Jan 2026 18:21:26 +0100
Subject: [PATCH v1 2/2] Add syscache for pg_inherits lookups
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Commit 90eae926a introduced calls to get_partition_ancestors() in
ExecInitPartitionInfo() to handle ON CONFLICT with REINDEX CONCURRENTLY
on partitioned tables.  That commit noted that get_partition_ancestors()
is slow because it scans pg_inherits each time, and suggested adding a
syscache.

This commit implements that suggestion by adding a new syscache
INHRELIDSEQNO on the pg_inherits_relid_seqno_index.  The
get_partition_parent_worker() function now uses SearchSysCache2()
instead of a direct catalog scan, which benefits both
get_partition_parent() and get_partition_ancestors().

Author: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/202512021255.r3ouzsfyxg5r%40alvherre.pgsql
---
 src/backend/catalog/partition.c      | 49 +++++++---------------------
 src/backend/executor/execPartition.c |  3 --
 src/include/catalog/pg_inherits.h    |  1 +
 3 files changed, 13 insertions(+), 40 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 28f3cade6ff..9b2528b9e8a 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -31,10 +31,8 @@
 #include "utils/rel.h"
 #include "utils/syscache.h"
 
-static Oid	get_partition_parent_worker(Relation inhRel, Oid relid,
-										bool *detach_pending);
-static void get_partition_ancestors_worker(Relation inhRel, Oid relid,
-										   List **ancestors);
+static Oid	get_partition_parent_worker(Oid relid, bool *detach_pending);
+static void get_partition_ancestors_worker(Oid relid, List **ancestors);
 
 /*
  * get_partition_parent
@@ -52,14 +50,10 @@ static void get_partition_ancestors_worker(Relation inhRel, Oid relid,
 Oid
 get_partition_parent(Oid relid, bool even_if_detached)
 {
-	Relation	catalogRelation;
 	Oid			result;
 	bool		detach_pending;
 
-	catalogRelation = table_open(InheritsRelationId, AccessShareLock);
-
-	result = get_partition_parent_worker(catalogRelation, relid,
-										 &detach_pending);
+	result = get_partition_parent_worker(relid, &detach_pending);
 
 	if (!OidIsValid(result))
 		elog(ERROR, "could not find tuple for parent of relation %u", relid);
@@ -68,8 +62,6 @@ get_partition_parent(Oid relid, bool even_if_detached)
 		elog(ERROR, "relation %u has no parent because it's being detached",
 			 relid);
 
-	table_close(catalogRelation, AccessShareLock);
-
 	return result;
 }
 
@@ -82,27 +74,16 @@ get_partition_parent(Oid relid, bool even_if_detached)
  * original parent is still returned.)
  */
 static Oid
-get_partition_parent_worker(Relation inhRel, Oid relid, bool *detach_pending)
+get_partition_parent_worker(Oid relid, bool *detach_pending)
 {
-	SysScanDesc scan;
-	ScanKeyData key[2];
 	Oid			result = InvalidOid;
 	HeapTuple	tuple;
 
 	*detach_pending = false;
 
-	ScanKeyInit(&key[0],
-				Anum_pg_inherits_inhrelid,
-				BTEqualStrategyNumber, F_OIDEQ,
-				ObjectIdGetDatum(relid));
-	ScanKeyInit(&key[1],
-				Anum_pg_inherits_inhseqno,
-				BTEqualStrategyNumber, F_INT4EQ,
-				Int32GetDatum(1));
-
-	scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, true,
-							  NULL, 2, key);
-	tuple = systable_getnext(scan);
+	tuple = SearchSysCache2(INHRELIDSEQNO,
+							ObjectIdGetDatum(relid),
+							Int32GetDatum(1));
 	if (HeapTupleIsValid(tuple))
 	{
 		Form_pg_inherits form = (Form_pg_inherits) GETSTRUCT(tuple);
@@ -111,10 +92,9 @@ get_partition_parent_worker(Relation inhRel, Oid relid, bool *detach_pending)
 		if (form->inhdetachpending)
 			*detach_pending = true;
 		result = form->inhparent;
+		ReleaseSysCache(tuple);
 	}
 
-	systable_endscan(scan);
-
 	return result;
 }
 
@@ -134,13 +114,8 @@ List *
 get_partition_ancestors(Oid relid)
 {
 	List	   *result = NIL;
-	Relation	inhRel;
 
-	inhRel = table_open(InheritsRelationId, AccessShareLock);
-
-	get_partition_ancestors_worker(inhRel, relid, &result);
-
-	table_close(inhRel, AccessShareLock);
+	get_partition_ancestors_worker(relid, &result);
 
 	return result;
 }
@@ -150,7 +125,7 @@ get_partition_ancestors(Oid relid)
  *		recursive worker for get_partition_ancestors
  */
 static void
-get_partition_ancestors_worker(Relation inhRel, Oid relid, List **ancestors)
+get_partition_ancestors_worker(Oid relid, List **ancestors)
 {
 	Oid			parentOid;
 	bool		detach_pending;
@@ -159,12 +134,12 @@ get_partition_ancestors_worker(Relation inhRel, Oid relid, List **ancestors)
 	 * Recursion ends at the topmost level, ie., when there's no parent; also
 	 * when the partition is being detached.
 	 */
-	parentOid = get_partition_parent_worker(inhRel, relid, &detach_pending);
+	parentOid = get_partition_parent_worker(relid, &detach_pending);
 	if (parentOid == InvalidOid || detach_pending)
 		return;
 
 	*ancestors = lappend_oid(*ancestors, parentOid);
-	get_partition_ancestors_worker(inhRel, parentOid, ancestors);
+	get_partition_ancestors_worker(parentOid, ancestors);
 }
 
 /*
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index 73f8afc0755..4a3e3aea447 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -776,9 +776,6 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
 				 * Otherwise, if this index has no parent, track it for later,
 				 * in case REINDEX CONCURRENTLY is working on one of the
 				 * arbiters.
-				 *
-				 * XXX get_partition_ancestors is slow: it scans pg_inherits
-				 * each time.  Consider a syscache or some other way to cache?
 				 */
 				indexoid = RelationGetRelid(leaf_part_rri->ri_IndexRelationDescs[listidx]);
 				ancestors = get_partition_ancestors(indexoid);
diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h
index c14aee773c3..5a785eca1cf 100644
--- a/src/include/catalog/pg_inherits.h
+++ b/src/include/catalog/pg_inherits.h
@@ -47,6 +47,7 @@ typedef FormData_pg_inherits *Form_pg_inherits;
 DECLARE_UNIQUE_INDEX_PKEY(pg_inherits_relid_seqno_index, 2680, InheritsRelidSeqnoIndexId, pg_inherits, btree(inhrelid oid_ops, inhseqno int4_ops));
 DECLARE_INDEX(pg_inherits_parent_index, 2187, InheritsParentIndexId, pg_inherits, btree(inhparent oid_ops));
 
+MAKE_SYSCACHE(INHRELIDSEQNO, pg_inherits_relid_seqno_index, 16);
 
 extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode);
 extern List *find_inheritance_children_extended(Oid parentrelId, bool omit_detached,
-- 
2.43.0

